快速打印可变内存地址。

时间:2022-04-15 23:08:41

Is there anyway to simulate the [NSString stringWithFormat:@"%p", myVar] code in the new swift language ?

在新的swift语言中,是否存在对[NSString stringWithFormat:@"%p", myVar]代码的模拟?

For example:

例如:

let str = "A String"
println(" str value \(str) has address: ?")

14 个解决方案

#1


91  

Swift 2

This is now part of the standard library: unsafeAddressOf.

这是标准库的一部分:unsafeAddressOf。

/// Return an UnsafePointer to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object

Swift 3

For Swift 3, use withUnsafePointer:

对于Swift 3,使用withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}

#2


56  

Swift 3.1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())

Prints the memory address of someVar.

打印someVar的内存地址。


Swift 4:

print(Unmanaged.passUnretained(someVar).toOpaque())

Prints the memory address of someVar. (thanks to @Ying)

打印someVar的内存地址。(由于@Ying)


#3


51  

Note that this answer was quite old. Many of the methods it describes no longer work. Specifically .core cannot be accessed anymore.

注意,这个答案相当古老。它描述的许多方法都不再有效。特别是。核心不能被访问。

However @drew's answer is correct and simple:

然而,@drew的回答正确而简单:

This is now part of the standard library: unsafeAddressOf.

这是标准库的一部分:unsafeAddressOf。

So the answer to your questions is:

所以你的问题的答案是:

println(" str value \(str) has address: \(unsafeAddressOf(str))")

Here is the original answer that was marked correct (for posterity/politeness):

以下是被标记为正确的原始答案(对于后代/礼貌):

Swift "hides" pointers, but they still exists under the hood. (because the runtime needs it, and for compatibility reasons with Objc and C)

Swift“隐藏”指针,但它们仍然存在于引擎盖下。(因为运行时需要它,出于兼容性的原因与Objc和C)

There are few things to know however, but first how to print the memory address of a Swift String?

但是,要知道的事情很少,但是首先如何打印一个Swift字符串的内存地址呢?

    var aString : String = "THIS IS A STRING"
    NSLog("%p", aString.core._baseAddress)  // _baseAddress is a COpaquePointer
   // example printed address 0x100006db0

This prints the memory address of the string, if you open XCode -> Debug Workflow -> View Memory and go to the printed address, you will see the raw data of the string. Since this is a string literal, this is a memory address inside the storage of the binary (not stack or heap).

这将打印字符串的内存地址,如果您打开XCode ->调试工作流->视图内存并到打印地址,您将看到字符串的原始数据。由于这是一个字符串文字,所以这是二进制文件存储中的一个内存地址(不是堆栈或堆)。

However, if you do

然而,如果你做的事情

    var aString : String = "THIS IS A STRING" + "This is another String"
    NSLog("%p", aString.core._baseAddress)

    // example printed address 0x103f30020

This will be on the stack, because the string is created at runtime

这将在堆栈上,因为字符串是在运行时创建的。

NOTE: .core._baseAddress is not documented, I found it looking in the variable inspector, and it may be hidden in the future

注意:.core。_baseAddress没有文档化,我发现它查找变量检查器,它可能隐藏在将来。

_baseAddress is not available on all types, here another example with a CInt

_baseAddress在所有类型上都不可用,这里还有一个带有CInt的例子。

    var testNumber : CInt = 289
    takesInt(&testNumber)

Where takesInt is a C helper function like this

takesInt是一个像这样的C助手函数?

void takesInt(int *intptr)
{
    printf("%p", intptr);
}

On the Swift side, this function is takesInt(intptr: CMutablePointer<CInt>), so it takes a CMutablePointer to a CInt, and you can obtain it with &varname

在Swift方面,这个函数是takesInt(intptr: CMutablePointer ),因此它将一个CMutablePointer指向一个CInt,您可以使用&varname获取它。

The function prints 0x7fff5fbfed98, an at this memory address you will find 289 (in hexadecimal notation). You can change its content with *intptr = 123456

该函数将打印0x7fff5fbfed98,在这个内存地址中,您将找到289(在十六进制表示法中)。您可以使用*intptr = 123456更改其内容。

Now, some other things to know.

现在,还有一些事情要知道。

String, in swift, is a primitive type, not an object.
CInt is a Swift type mapped to the C int Type.
If you want the memory address of an object, you have to do something different.
Swift has some Pointer Types that can be used when interacting with C, and you can read about them here: Swift Pointer Types
Moreover, you can understand more about them exploring their declaration (cmd+click on the type), to understand how to convert a type of pointer into another

在swift中,字符串是一种原始类型,而不是对象。CInt是一个快速类型映射到C int类型。如果你想要一个对象的内存地址,你必须做一些不同的事情。Swift有一些可以在与C交互时使用的指针类型,您可以在这里看到它们:Swift指针类型,您可以了解更多关于它们的信息,了解它们的声明(cmd+单击类型),了解如何将一种指针转换为另一种指针。

    var aString : NSString = "This is a string"  // create an NSString
    var anUnmanaged = Unmanaged<NSString>.passUnretained(aString)   // take an unmanaged pointer
    var opaque : COpaquePointer = anUnmanaged.toOpaque()   // convert it to a COpaquePointer
    var mut : CMutablePointer = &opaque   // this is a CMutablePointer<COpaquePointer>

    printptr(mut)   // pass the pointer to an helper function written in C

printptr is a C helper function I created, with this implementation

printptr是我创建的一个C助手函数,使用这个实现。

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}

Again, an example of the address printed: 0x6000000530b0 , and if you go through memory inspector you will find your NSString

同样,打印地址的示例:0x6000000530b0,如果您通过内存检查器,您将找到您的NSString。

One thing you can do with pointers in Swift (this can even be done with inout parameters)

你可以用Swift的指针做一件事(这甚至可以用inout参数来完成)

    func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) 
    {
        stringa.memory = "String Updated";
    }

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)

Or, interacting with Objc / c

或者,与Objc / c交互。

// objc side
+ (void)writeString:(void **)var
{
    NSMutableString *aString = [[NSMutableString alloc] initWithFormat:@"pippo %@", @"pluto"];
    *var = (void *)CFBridgingRetain(aString);   // Retain!
}

// swift side
var opaque = COpaquePointer.null()   // create a new opaque pointer pointing to null
TestClass.writeString(&opaque)
var string = Unmanaged<NSString>.fromOpaque(opaque).takeRetainedValue()
println(string)
// this prints pippo pluto

#4


16  

To get the (heap) address of an object

func address<T: AnyObject>(o: T) -> Int {
    return unsafeBitCast(o, Int.self)
}

class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970

(Edit: Swift 1.2 now includes a similar function called unsafeAddressOf.)

(编辑:Swift 1.2现在包括一个类似的功能,名为unsafeAddressOf。)

In Objective-C this would be [NSString stringWithFormat:@"%p", o].

在Objective-C中,这将是[NSString stringWithFormat:@"%p", o]。

o is a reference to the instance. So if o is assigned to another variable o2, the returned address for o2 will be the same.

o是对实例的引用。所以如果o被分配给另一个变量o2,那么o2的返回地址将是相同的。

This doesn't apply to structs (including String) and primitive types (like Int), because those live directly on the stack. But we can retrieve the location on the stack.

这并不适用于结构(包括字符串)和基本类型(比如Int),因为它们直接位于堆栈上。但是我们可以检索堆栈上的位置。

To get the (stack) address of a struct, build-in type or object reference

func address(o: UnsafePointer<Void>) -> Int {
    return unsafeBitCast(o, Int.self)
}

println(NSString(format: "%p", address(&o))) // -> 0x10de02ce0

var s = "A String"
println(NSString(format: "%p", address(&s))) // -> 0x10de02ce8

var i = 55
println(NSString(format: "%p", address(&i))) // -> 0x10de02d00

In Objective-C this would be [NSString stringWithFormat:@"%p", &o] or [NSString stringWithFormat:@"%p", &i].

在Objective-C中,这将是[NSString stringWithFormat:@"%p", &o]或[NSString stringWithFormat:@"%p", &i]。

s is struct. So if s is assigned to another variable s2, the value will be copied and the returned address for s2 will be different.

s是结构体。因此,如果s被分配给另一个变量s2,那么该值将被复制,而s2的返回地址将是不同的。

How it fits together (pointer recap)

Like in Objective-C, there are two different addresses associated with o. The first is the location of the object, the second is the location of the reference (or pointer) to the object.

在Objective-C中,有两个不同的地址与o相关联。第一个是对象的位置,第二个是指向对象的引用(或指针)的位置。

Yes, this means that the content of address 0x7fff5fbfe658 is the number 0x6100000011d0 as the debugger can tell us:

是的,这意味着地址0x7fff5fbfe658的内容是数字0x6100000011d0,因为调试器可以告诉我们:

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0

So, except for strings being structs, internally this all pretty much works the same as in (Objective-)C.

所以,除了字符串是struct,在内部这几乎和(Objective-)C是一样的。

(Current as of Xcode 6.3)

(Xcode 6.3的电流)

#5


11  

TL;DR

博士TL;

struct MemoryAddress<T>: CustomStringConvertible {

    let intValue: Int

    var description: String {
        let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
        return String(format: "%0\(length)p", intValue)
    }

    // for structures
    init(of structPointer: UnsafePointer<T>) {
        intValue = Int(bitPattern: structPointer)
    }
}

extension MemoryAddress where T: AnyObject {

    // for classes
    init(of classInstance: T) {
        intValue = unsafeBitCast(classInstance, to: Int.self)
        // or      Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
    }
}

/* Testing */

class MyClass { let foo = 42 }
var classInstance = MyClass()
let classInstanceAddress = MemoryAddress(of: classInstance) // and not &classInstance
print(String(format: "%018p", classInstanceAddress.intValue))
print(classInstanceAddress)

struct MyStruct { let foo = 1 } // using empty struct gives weird results (see comments)
var structInstance = MyStruct()
let structInstanceAddress = MemoryAddress(of: &structInstance)
print(String(format: "%018p", structInstanceAddress.intValue))
print(structInstanceAddress)

/* output
0x0000000101009b40
0x0000000101009b40
0x00000001005e3000
0x00000001005e3000
*/

(Gist)

(要点)


In Swift we deal either with value types (structures) or reference types (classes). When doing:

在Swift中,我们可以处理值类型(结构)或引用类型(类)。当进行:

let n = 42 // Int is a structure, i.e. value type

Some memory is allocated at address X, and at this address we will find the value 42. Doing &n creates a pointer pointing to address X, therefore &n tells us where n is located.

一些内存是在地址X分配的,在这个地址,我们将找到值42。做和n创建一个指向地址X的指针,因此n告诉我们n在哪里。

(lldb) frame variable -L n
0x00000001005e2e08: (Int) n = 42
(lldb) memory read -c 8 0x00000001005e2e08
0x1005e2e08: 2a 00 00 00 00 00 00 00 // 0x2a is 42

When doing:

当进行:

class C { var foo = 42, bar = 84 }
var c = C()

Memory is allocated in two places:

内存分配在两个地方:

  • at address Y where the class instance data is located and
  • 在地址Y中,类实例数据所在的位置。
  • at address X where the class instance reference is located.
  • 在类实例引用所在的地址X。

As said, classes are reference types: so the value of c is located at address X, at which we'll find the value of Y. And at address Y + 16 we'll find foo and at address Y + 24 we'll find bar (at + 0 and + 8 we'll find type data and reference counts, I can't tell you much more about this...).

说,类是引用类型:所以c位于地址X的值,我们会发现Y的值和在地址Y + 16我们会找到foo和地址Y + 24我们会发现酒吧(+ 0,+ 8我们会找到类型数据和引用计数,我不能告诉你更多关于这个…)。

(lldb) frame variable c // gives us address Y
(testmem.C) c = 0x0000000101a08f90 (foo = 42, bar = 84)
(lldb) memory read 0x0000000101a08f90 // reading memory at address Y
0x101a08f90: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00
0x101a08fa0: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00

0x2a is 42 (foo) and 0x54 is 84 (bar).

0x2a是42 (foo), 0x54是84 (bar)。

In both cases, using &n or &c will give us address X. For value types, that's what we want, but isn't for reference types.

在这两种情况下,使用&n或&c将给我们提供地址x。对于值类型,这是我们想要的,但不是用于引用类型。

When doing:

当进行:

let referencePointer = UnsafeMutablePointer<C>(&c)

We create a pointer on the reference, i.e. a pointer that points to address X. Same thing when using withUnsafePointer(&c) {}.

我们在引用上创建一个指针,即指向地址x的指针,在使用withUnsafePointer(&c){}时也会创建一个指针。

(lldb) frame variable referencePointer
(UnsafeMutablePointer<testmem.C>) referencePointer = 0x00000001005e2e00 // address X
(lldb) memory read -c 8 0x00000001005e2e00 // read memory at address X
0x1005e2e00: 20 ec 92 01 01 00 00 00 // contains address Y, consistent with result below:
(lldb) frame variable c
(testmem.C) c = 0x000000010192ec20 (foo = 42, bar = 84)

Now that we have a better understanding of what goes on under the hood, and that we now that at address X we'll find address Y (which is the one we want) we can do the following to get it:

现在我们更好地理解了引擎盖下发生了什么,我们现在在地址X上找到了地址Y(这是我们想要的)我们可以用下面的方法来得到它:

let addressY = unsafeBitCast(c, to: Int.self)

Verifying:

验证:

(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)

There are other ways to do this:

还有其他的方法:

let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }

toOpaque() actually calls unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

to()实际上是调用unsafeBitCast(c, to: UnsafeMutableRawPointer.self)。

I hope this helped... it did for me ????.

我希望这帮助……它对我来说????.

#6


7  

Reference Types:

  • It makes sense to get the memory address of a reference type as it represents identity.
  • 获取引用类型的内存地址是有意义的,因为它表示身份。
  • === identity operator is used to check 2 objects point to the same reference.
  • ===身份操作符用于检查两个对象指向相同的引用。
  • Use ObjectIdentifier to get the memory address
  • 使用ObjectIdentifier获取内存地址。

Code:

class C {}

let c1 = C()
let c2 = c1

//Option 1:
print("c1 address: \(Unmanaged.passUnretained(c1).toOpaque())") 

//Option 2:
let o1 = ObjectIdentifier(c1)
let o2 = ObjectIdentifier(c2)

print("o1 -> c1 = \(o1)")
print("o2 -> c2 = \(o2)")

if o1 == o2 {
    print("c1 = c2")
} else {
    print("c1 != c2")
}

//Output:
//c1 address: 0x000060c000005b10
//o1 -> c1 = ObjectIdentifier(0x000060c000005b10)
//o2 -> c2 = ObjectIdentifier(0x000060c000005b10)
//c1 = c2

Value Types:

  • The need to get the memory address of a value type is not of much significance (as it is a value) and the emphasis would be more on the equality of the value.
  • 获取值类型的内存地址的需要没有多大意义(因为它是一个值),而重点将更多地放在值的平等性上。

#7


6  

If you just want to see this in the debugger and not do anything else with it, there's no need to actually get the Int pointer. To get the string representation of an object's address in memory, just use something like this:

如果你只是想在调试器中看到这个,而不是用它来做其他的事情,就没有必要实际得到Int指针。要获取内存中对象地址的字符串表示,只需使用如下所示:

public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's target or place the logic in a global function
    public var pointerString: String {
        return String(format: "%p", self)
    }
}

Example usage:

使用示例:

print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...

Additionally, remember that you can simply print an object without overriding its description, and it will show its pointer address alongside more descriptive (if oft cryptic) text.

另外,请记住,您可以简单地打印一个对象,而不需要重写它的描述,并且它将显示它的指针地址,以及更多的描述性的(如果经常是含糊的)文本。

print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...

#8


4  

The other answers are fine, though I was looking for a way to get the pointer address as an integer:

其他的答案都很好,尽管我正在寻找一种将指针地址作为整数的方法:

let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int

Just a little follow-up.

只是有点随访。

#9


4  

Swift 4

extension String {
    static func pointer(_ object: AnyObject?) -> String {
        guard let object = object else { return "nil" }
        let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
        return String(describing: opaque)
    }
}

Usage:

print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698

print("nil: \(String.pointer(nil))")
// nil: nil

#10


3  

The answer @Drew provide can only be used for class type.
The answer @nschum provide can only be for struct type.

@Drew提供的答案只能用于类类型。@nschum提供的答案只能是struct类型。

However if you use the second method to get address of a array with value type element. Swift will copy the whole array because in Swift array is copy-on-write and Swift can't make sure it behave this way once it pass control over to C/C++ (Which is trigger by using & to get address). And if you use first method instead , it will automatically convert Array to NSArray which is surely something we don't want.

但是,如果您使用第二种方法来获得带有值类型元素的数组的地址。Swift将复制整个数组,因为在Swift数组中,copy-on-write和Swift不能确保它在将控制权传递给C/ c++(通过使用&获取地址触发)时,就会这样做。如果你使用第一种方法,它会自动将数组转换为NSArray,这肯定是我们不想要的。

So the most simple and unified way I found is using lldb instruction frame variable -L yourVariableName.

我找到的最简单和统一的方法是使用lldb指令框架变量-L yourVariableName。

Or you can combine their answers:

或者你可以结合他们的答案:

func address(o: UnsafePointer<Void>) {
    let addr = unsafeBitCast(o, Int.self)
    print(NSString(format: "%p", addr))
}

func address<T: AnyObject>(o: T) -> String{
    let addr = unsafeBitCast(o, Int.self)
    return NSString(format: "%p", addr) as String
}

#11


3  

This is for Swift 3.

这是给斯威夫特3的。

Like @CharlieMonroe I wanted to get the address as an integer. Specifically, I wanted the address of a Thread object for use as a thread ID in a diagnostic logging module, for situations where no thread name was available.

像@CharlieMonroe,我想把地址作为一个整数。具体来说,我想要一个线程对象的地址,作为诊断日志模块中的线程ID,在没有线程名称的情况下使用。

Based on Charlie Monroe's code, here's what I've come up with so far. But beware, I'm very new to Swift, this may not be correct ...

根据查理·门罗的代码,这是我到目前为止所提出的。但要小心,我对斯威夫特很陌生,这可能不正确……

  // Convert the memory address of the current Thread object into an Int for use as a thread ID
  let objPtr = Unmanaged.passUnretained(Thread.current).toOpaque()
  let onePtr = UnsafeMutableRawPointer(bitPattern: 1)!  // 1 used instead of 0 to avoid crash
  let rawAddress : Int64 = onePtr.distance(to: objPtr) + 1  // This may include some high-order bits
  let address = rawAddress % (256 * 1024 * 1024 * 1024)  // Remove high-order bits

The last statement is there because without it I was getting addresses like 0x60000007DB3F. The modulo operation in the last statement converts that into 0x7DB3F.

最后一个语句,因为没有它,我得到的地址是0x60000007DB3F。最后一个语句中的模块操作将其转换为0x7DB3F。

#12


3  

My solution on Swift 3

我的解决方案在斯威夫特3。

extension MyClass: CustomStringConvertible {
    var description: String {
        return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
    }
}

this code create description like default description <MyClass: 0x610000223340>

此代码创建描述,如默认描述

#13


3  

In Swift4 about Array:

在Swift4数组:

    let array1 = [1,2,3]
    let array2 = array1
    array1.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }
    array2.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }

#14


2  

This is certainly not the fastest or safest way to go about it. But it works for me. This will allow for any nsobject subclass to adopt this property.

这肯定不是最快或最安全的方法。但这对我很有效。这将允许任何nsobject子类采用此属性。

public extension NSObject {
    public var memoryAddress : String? {
        let str = "\(self.self)".components(separatedBy: ": ")
        guard str.count > 1 else { return nil }
        return str[1].replacingOccurrences(of: ">", with: "")            
    }
}

//usage 
let foo : String! = "hello"
Swift.print(foo.memoryAddress) // prints 0x100f12980

#1


91  

Swift 2

This is now part of the standard library: unsafeAddressOf.

这是标准库的一部分:unsafeAddressOf。

/// Return an UnsafePointer to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object

Swift 3

For Swift 3, use withUnsafePointer:

对于Swift 3,使用withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}

#2


56  

Swift 3.1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())

Prints the memory address of someVar.

打印someVar的内存地址。


Swift 4:

print(Unmanaged.passUnretained(someVar).toOpaque())

Prints the memory address of someVar. (thanks to @Ying)

打印someVar的内存地址。(由于@Ying)


#3


51  

Note that this answer was quite old. Many of the methods it describes no longer work. Specifically .core cannot be accessed anymore.

注意,这个答案相当古老。它描述的许多方法都不再有效。特别是。核心不能被访问。

However @drew's answer is correct and simple:

然而,@drew的回答正确而简单:

This is now part of the standard library: unsafeAddressOf.

这是标准库的一部分:unsafeAddressOf。

So the answer to your questions is:

所以你的问题的答案是:

println(" str value \(str) has address: \(unsafeAddressOf(str))")

Here is the original answer that was marked correct (for posterity/politeness):

以下是被标记为正确的原始答案(对于后代/礼貌):

Swift "hides" pointers, but they still exists under the hood. (because the runtime needs it, and for compatibility reasons with Objc and C)

Swift“隐藏”指针,但它们仍然存在于引擎盖下。(因为运行时需要它,出于兼容性的原因与Objc和C)

There are few things to know however, but first how to print the memory address of a Swift String?

但是,要知道的事情很少,但是首先如何打印一个Swift字符串的内存地址呢?

    var aString : String = "THIS IS A STRING"
    NSLog("%p", aString.core._baseAddress)  // _baseAddress is a COpaquePointer
   // example printed address 0x100006db0

This prints the memory address of the string, if you open XCode -> Debug Workflow -> View Memory and go to the printed address, you will see the raw data of the string. Since this is a string literal, this is a memory address inside the storage of the binary (not stack or heap).

这将打印字符串的内存地址,如果您打开XCode ->调试工作流->视图内存并到打印地址,您将看到字符串的原始数据。由于这是一个字符串文字,所以这是二进制文件存储中的一个内存地址(不是堆栈或堆)。

However, if you do

然而,如果你做的事情

    var aString : String = "THIS IS A STRING" + "This is another String"
    NSLog("%p", aString.core._baseAddress)

    // example printed address 0x103f30020

This will be on the stack, because the string is created at runtime

这将在堆栈上,因为字符串是在运行时创建的。

NOTE: .core._baseAddress is not documented, I found it looking in the variable inspector, and it may be hidden in the future

注意:.core。_baseAddress没有文档化,我发现它查找变量检查器,它可能隐藏在将来。

_baseAddress is not available on all types, here another example with a CInt

_baseAddress在所有类型上都不可用,这里还有一个带有CInt的例子。

    var testNumber : CInt = 289
    takesInt(&testNumber)

Where takesInt is a C helper function like this

takesInt是一个像这样的C助手函数?

void takesInt(int *intptr)
{
    printf("%p", intptr);
}

On the Swift side, this function is takesInt(intptr: CMutablePointer<CInt>), so it takes a CMutablePointer to a CInt, and you can obtain it with &varname

在Swift方面,这个函数是takesInt(intptr: CMutablePointer ),因此它将一个CMutablePointer指向一个CInt,您可以使用&varname获取它。

The function prints 0x7fff5fbfed98, an at this memory address you will find 289 (in hexadecimal notation). You can change its content with *intptr = 123456

该函数将打印0x7fff5fbfed98,在这个内存地址中,您将找到289(在十六进制表示法中)。您可以使用*intptr = 123456更改其内容。

Now, some other things to know.

现在,还有一些事情要知道。

String, in swift, is a primitive type, not an object.
CInt is a Swift type mapped to the C int Type.
If you want the memory address of an object, you have to do something different.
Swift has some Pointer Types that can be used when interacting with C, and you can read about them here: Swift Pointer Types
Moreover, you can understand more about them exploring their declaration (cmd+click on the type), to understand how to convert a type of pointer into another

在swift中,字符串是一种原始类型,而不是对象。CInt是一个快速类型映射到C int类型。如果你想要一个对象的内存地址,你必须做一些不同的事情。Swift有一些可以在与C交互时使用的指针类型,您可以在这里看到它们:Swift指针类型,您可以了解更多关于它们的信息,了解它们的声明(cmd+单击类型),了解如何将一种指针转换为另一种指针。

    var aString : NSString = "This is a string"  // create an NSString
    var anUnmanaged = Unmanaged<NSString>.passUnretained(aString)   // take an unmanaged pointer
    var opaque : COpaquePointer = anUnmanaged.toOpaque()   // convert it to a COpaquePointer
    var mut : CMutablePointer = &opaque   // this is a CMutablePointer<COpaquePointer>

    printptr(mut)   // pass the pointer to an helper function written in C

printptr is a C helper function I created, with this implementation

printptr是我创建的一个C助手函数,使用这个实现。

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}

Again, an example of the address printed: 0x6000000530b0 , and if you go through memory inspector you will find your NSString

同样,打印地址的示例:0x6000000530b0,如果您通过内存检查器,您将找到您的NSString。

One thing you can do with pointers in Swift (this can even be done with inout parameters)

你可以用Swift的指针做一件事(这甚至可以用inout参数来完成)

    func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) 
    {
        stringa.memory = "String Updated";
    }

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)

Or, interacting with Objc / c

或者,与Objc / c交互。

// objc side
+ (void)writeString:(void **)var
{
    NSMutableString *aString = [[NSMutableString alloc] initWithFormat:@"pippo %@", @"pluto"];
    *var = (void *)CFBridgingRetain(aString);   // Retain!
}

// swift side
var opaque = COpaquePointer.null()   // create a new opaque pointer pointing to null
TestClass.writeString(&opaque)
var string = Unmanaged<NSString>.fromOpaque(opaque).takeRetainedValue()
println(string)
// this prints pippo pluto

#4


16  

To get the (heap) address of an object

func address<T: AnyObject>(o: T) -> Int {
    return unsafeBitCast(o, Int.self)
}

class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970

(Edit: Swift 1.2 now includes a similar function called unsafeAddressOf.)

(编辑:Swift 1.2现在包括一个类似的功能,名为unsafeAddressOf。)

In Objective-C this would be [NSString stringWithFormat:@"%p", o].

在Objective-C中,这将是[NSString stringWithFormat:@"%p", o]。

o is a reference to the instance. So if o is assigned to another variable o2, the returned address for o2 will be the same.

o是对实例的引用。所以如果o被分配给另一个变量o2,那么o2的返回地址将是相同的。

This doesn't apply to structs (including String) and primitive types (like Int), because those live directly on the stack. But we can retrieve the location on the stack.

这并不适用于结构(包括字符串)和基本类型(比如Int),因为它们直接位于堆栈上。但是我们可以检索堆栈上的位置。

To get the (stack) address of a struct, build-in type or object reference

func address(o: UnsafePointer<Void>) -> Int {
    return unsafeBitCast(o, Int.self)
}

println(NSString(format: "%p", address(&o))) // -> 0x10de02ce0

var s = "A String"
println(NSString(format: "%p", address(&s))) // -> 0x10de02ce8

var i = 55
println(NSString(format: "%p", address(&i))) // -> 0x10de02d00

In Objective-C this would be [NSString stringWithFormat:@"%p", &o] or [NSString stringWithFormat:@"%p", &i].

在Objective-C中,这将是[NSString stringWithFormat:@"%p", &o]或[NSString stringWithFormat:@"%p", &i]。

s is struct. So if s is assigned to another variable s2, the value will be copied and the returned address for s2 will be different.

s是结构体。因此,如果s被分配给另一个变量s2,那么该值将被复制,而s2的返回地址将是不同的。

How it fits together (pointer recap)

Like in Objective-C, there are two different addresses associated with o. The first is the location of the object, the second is the location of the reference (or pointer) to the object.

在Objective-C中,有两个不同的地址与o相关联。第一个是对象的位置,第二个是指向对象的引用(或指针)的位置。

Yes, this means that the content of address 0x7fff5fbfe658 is the number 0x6100000011d0 as the debugger can tell us:

是的,这意味着地址0x7fff5fbfe658的内容是数字0x6100000011d0,因为调试器可以告诉我们:

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0

So, except for strings being structs, internally this all pretty much works the same as in (Objective-)C.

所以,除了字符串是struct,在内部这几乎和(Objective-)C是一样的。

(Current as of Xcode 6.3)

(Xcode 6.3的电流)

#5


11  

TL;DR

博士TL;

struct MemoryAddress<T>: CustomStringConvertible {

    let intValue: Int

    var description: String {
        let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
        return String(format: "%0\(length)p", intValue)
    }

    // for structures
    init(of structPointer: UnsafePointer<T>) {
        intValue = Int(bitPattern: structPointer)
    }
}

extension MemoryAddress where T: AnyObject {

    // for classes
    init(of classInstance: T) {
        intValue = unsafeBitCast(classInstance, to: Int.self)
        // or      Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
    }
}

/* Testing */

class MyClass { let foo = 42 }
var classInstance = MyClass()
let classInstanceAddress = MemoryAddress(of: classInstance) // and not &classInstance
print(String(format: "%018p", classInstanceAddress.intValue))
print(classInstanceAddress)

struct MyStruct { let foo = 1 } // using empty struct gives weird results (see comments)
var structInstance = MyStruct()
let structInstanceAddress = MemoryAddress(of: &structInstance)
print(String(format: "%018p", structInstanceAddress.intValue))
print(structInstanceAddress)

/* output
0x0000000101009b40
0x0000000101009b40
0x00000001005e3000
0x00000001005e3000
*/

(Gist)

(要点)


In Swift we deal either with value types (structures) or reference types (classes). When doing:

在Swift中,我们可以处理值类型(结构)或引用类型(类)。当进行:

let n = 42 // Int is a structure, i.e. value type

Some memory is allocated at address X, and at this address we will find the value 42. Doing &n creates a pointer pointing to address X, therefore &n tells us where n is located.

一些内存是在地址X分配的,在这个地址,我们将找到值42。做和n创建一个指向地址X的指针,因此n告诉我们n在哪里。

(lldb) frame variable -L n
0x00000001005e2e08: (Int) n = 42
(lldb) memory read -c 8 0x00000001005e2e08
0x1005e2e08: 2a 00 00 00 00 00 00 00 // 0x2a is 42

When doing:

当进行:

class C { var foo = 42, bar = 84 }
var c = C()

Memory is allocated in two places:

内存分配在两个地方:

  • at address Y where the class instance data is located and
  • 在地址Y中,类实例数据所在的位置。
  • at address X where the class instance reference is located.
  • 在类实例引用所在的地址X。

As said, classes are reference types: so the value of c is located at address X, at which we'll find the value of Y. And at address Y + 16 we'll find foo and at address Y + 24 we'll find bar (at + 0 and + 8 we'll find type data and reference counts, I can't tell you much more about this...).

说,类是引用类型:所以c位于地址X的值,我们会发现Y的值和在地址Y + 16我们会找到foo和地址Y + 24我们会发现酒吧(+ 0,+ 8我们会找到类型数据和引用计数,我不能告诉你更多关于这个…)。

(lldb) frame variable c // gives us address Y
(testmem.C) c = 0x0000000101a08f90 (foo = 42, bar = 84)
(lldb) memory read 0x0000000101a08f90 // reading memory at address Y
0x101a08f90: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00
0x101a08fa0: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00

0x2a is 42 (foo) and 0x54 is 84 (bar).

0x2a是42 (foo), 0x54是84 (bar)。

In both cases, using &n or &c will give us address X. For value types, that's what we want, but isn't for reference types.

在这两种情况下,使用&n或&c将给我们提供地址x。对于值类型,这是我们想要的,但不是用于引用类型。

When doing:

当进行:

let referencePointer = UnsafeMutablePointer<C>(&c)

We create a pointer on the reference, i.e. a pointer that points to address X. Same thing when using withUnsafePointer(&c) {}.

我们在引用上创建一个指针,即指向地址x的指针,在使用withUnsafePointer(&c){}时也会创建一个指针。

(lldb) frame variable referencePointer
(UnsafeMutablePointer<testmem.C>) referencePointer = 0x00000001005e2e00 // address X
(lldb) memory read -c 8 0x00000001005e2e00 // read memory at address X
0x1005e2e00: 20 ec 92 01 01 00 00 00 // contains address Y, consistent with result below:
(lldb) frame variable c
(testmem.C) c = 0x000000010192ec20 (foo = 42, bar = 84)

Now that we have a better understanding of what goes on under the hood, and that we now that at address X we'll find address Y (which is the one we want) we can do the following to get it:

现在我们更好地理解了引擎盖下发生了什么,我们现在在地址X上找到了地址Y(这是我们想要的)我们可以用下面的方法来得到它:

let addressY = unsafeBitCast(c, to: Int.self)

Verifying:

验证:

(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)

There are other ways to do this:

还有其他的方法:

let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }

toOpaque() actually calls unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

to()实际上是调用unsafeBitCast(c, to: UnsafeMutableRawPointer.self)。

I hope this helped... it did for me ????.

我希望这帮助……它对我来说????.

#6


7  

Reference Types:

  • It makes sense to get the memory address of a reference type as it represents identity.
  • 获取引用类型的内存地址是有意义的,因为它表示身份。
  • === identity operator is used to check 2 objects point to the same reference.
  • ===身份操作符用于检查两个对象指向相同的引用。
  • Use ObjectIdentifier to get the memory address
  • 使用ObjectIdentifier获取内存地址。

Code:

class C {}

let c1 = C()
let c2 = c1

//Option 1:
print("c1 address: \(Unmanaged.passUnretained(c1).toOpaque())") 

//Option 2:
let o1 = ObjectIdentifier(c1)
let o2 = ObjectIdentifier(c2)

print("o1 -> c1 = \(o1)")
print("o2 -> c2 = \(o2)")

if o1 == o2 {
    print("c1 = c2")
} else {
    print("c1 != c2")
}

//Output:
//c1 address: 0x000060c000005b10
//o1 -> c1 = ObjectIdentifier(0x000060c000005b10)
//o2 -> c2 = ObjectIdentifier(0x000060c000005b10)
//c1 = c2

Value Types:

  • The need to get the memory address of a value type is not of much significance (as it is a value) and the emphasis would be more on the equality of the value.
  • 获取值类型的内存地址的需要没有多大意义(因为它是一个值),而重点将更多地放在值的平等性上。

#7


6  

If you just want to see this in the debugger and not do anything else with it, there's no need to actually get the Int pointer. To get the string representation of an object's address in memory, just use something like this:

如果你只是想在调试器中看到这个,而不是用它来做其他的事情,就没有必要实际得到Int指针。要获取内存中对象地址的字符串表示,只需使用如下所示:

public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's target or place the logic in a global function
    public var pointerString: String {
        return String(format: "%p", self)
    }
}

Example usage:

使用示例:

print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...

Additionally, remember that you can simply print an object without overriding its description, and it will show its pointer address alongside more descriptive (if oft cryptic) text.

另外,请记住,您可以简单地打印一个对象,而不需要重写它的描述,并且它将显示它的指针地址,以及更多的描述性的(如果经常是含糊的)文本。

print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...

#8


4  

The other answers are fine, though I was looking for a way to get the pointer address as an integer:

其他的答案都很好,尽管我正在寻找一种将指针地址作为整数的方法:

let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int

Just a little follow-up.

只是有点随访。

#9


4  

Swift 4

extension String {
    static func pointer(_ object: AnyObject?) -> String {
        guard let object = object else { return "nil" }
        let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
        return String(describing: opaque)
    }
}

Usage:

print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698

print("nil: \(String.pointer(nil))")
// nil: nil

#10


3  

The answer @Drew provide can only be used for class type.
The answer @nschum provide can only be for struct type.

@Drew提供的答案只能用于类类型。@nschum提供的答案只能是struct类型。

However if you use the second method to get address of a array with value type element. Swift will copy the whole array because in Swift array is copy-on-write and Swift can't make sure it behave this way once it pass control over to C/C++ (Which is trigger by using & to get address). And if you use first method instead , it will automatically convert Array to NSArray which is surely something we don't want.

但是,如果您使用第二种方法来获得带有值类型元素的数组的地址。Swift将复制整个数组,因为在Swift数组中,copy-on-write和Swift不能确保它在将控制权传递给C/ c++(通过使用&获取地址触发)时,就会这样做。如果你使用第一种方法,它会自动将数组转换为NSArray,这肯定是我们不想要的。

So the most simple and unified way I found is using lldb instruction frame variable -L yourVariableName.

我找到的最简单和统一的方法是使用lldb指令框架变量-L yourVariableName。

Or you can combine their answers:

或者你可以结合他们的答案:

func address(o: UnsafePointer<Void>) {
    let addr = unsafeBitCast(o, Int.self)
    print(NSString(format: "%p", addr))
}

func address<T: AnyObject>(o: T) -> String{
    let addr = unsafeBitCast(o, Int.self)
    return NSString(format: "%p", addr) as String
}

#11


3  

This is for Swift 3.

这是给斯威夫特3的。

Like @CharlieMonroe I wanted to get the address as an integer. Specifically, I wanted the address of a Thread object for use as a thread ID in a diagnostic logging module, for situations where no thread name was available.

像@CharlieMonroe,我想把地址作为一个整数。具体来说,我想要一个线程对象的地址,作为诊断日志模块中的线程ID,在没有线程名称的情况下使用。

Based on Charlie Monroe's code, here's what I've come up with so far. But beware, I'm very new to Swift, this may not be correct ...

根据查理·门罗的代码,这是我到目前为止所提出的。但要小心,我对斯威夫特很陌生,这可能不正确……

  // Convert the memory address of the current Thread object into an Int for use as a thread ID
  let objPtr = Unmanaged.passUnretained(Thread.current).toOpaque()
  let onePtr = UnsafeMutableRawPointer(bitPattern: 1)!  // 1 used instead of 0 to avoid crash
  let rawAddress : Int64 = onePtr.distance(to: objPtr) + 1  // This may include some high-order bits
  let address = rawAddress % (256 * 1024 * 1024 * 1024)  // Remove high-order bits

The last statement is there because without it I was getting addresses like 0x60000007DB3F. The modulo operation in the last statement converts that into 0x7DB3F.

最后一个语句,因为没有它,我得到的地址是0x60000007DB3F。最后一个语句中的模块操作将其转换为0x7DB3F。

#12


3  

My solution on Swift 3

我的解决方案在斯威夫特3。

extension MyClass: CustomStringConvertible {
    var description: String {
        return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
    }
}

this code create description like default description <MyClass: 0x610000223340>

此代码创建描述,如默认描述

#13


3  

In Swift4 about Array:

在Swift4数组:

    let array1 = [1,2,3]
    let array2 = array1
    array1.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }
    array2.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }

#14


2  

This is certainly not the fastest or safest way to go about it. But it works for me. This will allow for any nsobject subclass to adopt this property.

这肯定不是最快或最安全的方法。但这对我很有效。这将允许任何nsobject子类采用此属性。

public extension NSObject {
    public var memoryAddress : String? {
        let str = "\(self.self)".components(separatedBy: ": ")
        guard str.count > 1 else { return nil }
        return str[1].replacingOccurrences(of: ">", with: "")            
    }
}

//usage 
let foo : String! = "hello"
Swift.print(foo.memoryAddress) // prints 0x100f12980