快速打印可变内存地址

是否有模拟新的[NSString stringWithFormat:@"%p", myVar][NSString stringWithFormat:@"%p", myVar]代码?

例如:

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

Swift 2

这现在是标准库的一部分: 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

对于Swift 3,使用withUnsafePointer

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

请注意,这个答案是相当古老的。 它描述的许多方法不再有效。 具体的.core不能再被访问了。

不过@提请的答案是正确和简单的:

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

所以你的问题的答案是:

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

这是原来的答案是正确的(后代/礼貌):

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

然而,有几件事要知道,但首先如何打印一个Swiftstring的内存地址?

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

这将打印string的内存地址,如果打开XCode – > Debug Workflow – > View Memory并转到打印的地址,您将看到string的原始数据。 由于这是一个string字面值,因此这是二进制文件(不是堆栈或堆)存储器中的内存地址。

但是,如果你这样做

  var aString : String = "THIS IS A STRING" + "This is another String" NSLog("%p", aString.core._baseAddress) // example printed address 0x103f30020 

这将在堆栈中,因为string是在运行时创build的

注意:.core._baseAddress没有logging,我发现它在variables检查器中查找,并且可能在将来隐藏

_baseAddress在所有types中都不可用,这里是一个CInt的另一个例子

  var testNumber : CInt = 289 takesInt(&testNumber) 

其中takesInt是一个像这样的C帮助函数

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

在Swift方面,这个函数是takesInt(intptr: CMutablePointer<CInt>) ,所以它把一个CMutablePointer给一个CInt,并且你可以用&varname

该函数打印0x7fff5fbfed98 ,在这个内存地址你会发现289(hex符号)。 你可以用*intptr = 123456来改变它的内容

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

string,在swift中,是一个原始types,而不是一个对象。
CInt是映射到C inttypes的Swifttypes。
如果你想要一个对象的内存地址,你必须做一些不同的事情。
Swift有一些与C交互的指针types,你可以在这里阅读: Swift指针types
此外,你可以更多地了解他们探索他们的声明(cmd +点击types),了解如何将一种types的指针转​​换为另一种

  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是我用这个实现创build的一个C帮助器函数

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

再次,地址打印的例子: 0x6000000530b0 ,如果你通过内存检查你会发现你的NSString

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

  func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) { stringa.memory = "String Updated"; } var testString : NSString = "test string" println(testString) playWithPointer(&testString) println(testString) 

或者,与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 

Swift 3.1:

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

打印someVar的内存地址。

获取对象的(堆)地址

 func address<T: AnyObject>(o: T) -> Int { return unsafeBitCast(o, Int.self) } class Test {} var o = Test() println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970 

编辑: Swift 1.2现在包含一个类似的函数unsafeAddressOf 。)

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

o是对实例的引用。 所以如果o被分配给另一个variableso2o2的返回地址将是相同的。

这不适用于结构体(包括String )和原始types(如Int ),因为它们直接在堆栈上。 但是我们可以检索堆栈上的位置。

获取结构体的(堆栈)地址,内buildtypes或对象引用

 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 

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

s是结构。 因此,如果将s分配给另一个variabless2 ,则该值将被复制,并且s2的返回地址将会不同。

它如何适合在一起(指针回顾)

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

是的,这意味着地址0x7fff5fbfe658的内容是数字0x6100000011d0debugging器可以告诉我们:

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

所以,除了string是结构,内部这几乎和(Objective-)C中的一样。

(目前的Xcode 6.3)

如果你只是想在debugging器中看到这一点,而没有做任何其他的事情,那么就没有必要真正得到Int指针。 要在内存中获取对象地址的string表示forms,只需使用如下所示的内容:

 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) } } 

用法示例:

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

此外,请记住, 您可以简单地打印一个对象而不会覆盖其description ,并且会显示其指针地址以及更多的描述性(如果不是很神秘的)文本。

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

TL; DR

 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 )


在Swift中,我们处理值types(结构)或引用types(类)。 在做:

 let n = 42 // Int is a structure, ie value type 

一些内存被分配到地址X,在这个地址我们将会find值42.做&n创build一个指向地址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 

在做:

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

内存分配在两个地方:

  • 在类实例数据所在的地址Y处
  • 在类实例引用所在的地址X处。

如上所述,类是引用types:因此c的值位于地址X处,我们可以findY的值。在地址Y + 16处,我们将findfoo并在地址Y + 24处findbar (在+ 0和+8我们会发现types数据和引用计数,我不能告诉你更多关于这个…)。

 (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是42(foo), 0x54是84(bar)。

在这两种情况下,使用&n&c将给我们地址X.对于值types,这就是我们想要的,但不适用于引用types。

在做:

 let referencePointer = UnsafeMutablePointer<C>(&c) 

我们在引用上创build一个指针,也就是一个指向地址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) 

现在我们已经更好地理解了底层的内容,现在我们在地址X处find地址Y(这是我们想要的),我们可以做到以下几点:

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

validation:

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

还有其他方法可以做到这一点:

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

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

我希望这有助于…它为我做了😆。

其他的答案是好的,虽然我正在寻找一种方法来获取指针地址作为一个整数:

 let ptr = unsafeAddressOf(obj) let nullPtr = UnsafePointer<Void>(bitPattern: 0) /// This gets the address of pointer let address = nullPtr.distanceTo(ptr) // This is Int 

只是一点点后续。

@Drew提供的答案只能用于类types。
@nschum提供的答案只能用于结构types。

但是,如果使用第二种方法来获取具有值types元素的数组的地址。 Swift将复制整个数组,因为在Swift数组是写时复制和Swift不能确保它的行为一旦它通过控制到C / C ++(这是触发器使用&获取地址)。 如果你使用第一种方法,它会自动将Array转换为NSArray ,这肯定是我们不想要的东西。

所以我find的最简单和统一的方法是使用lldb指令frame variable -L yourVariableName

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

 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 } 

这是Swift 3。

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

基于查理·门罗的代码,这是我到目前为止所提出的。 但要小心,我对Swift很陌生,这可能是不正确的…

  // 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 

最后的声明是因为没有它,我得到像0x60000007DB3F地址。 最后一条语句中的模运算将其转换为0x7DB3F。

我在Swift 3上的解决scheme

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

此代码创build类似于默认描述<MyClass: 0x610000223340>描述

这当然不是最快或最安全的方法。 但它对我有用。 这将允许任何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 

参考types:

  • 获取引用types的内存地址是有意义的,因为它代表了标识。
  • ===同一性操作符用来检查2个对象是否指向同一个引用。
  • 使用ObjectIdentifier来获取内存地址

码:

 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 

价值types:

  • 获取值types的内存地址的需求并不重要(因为它是一个值),而重点更多地放在值的平等上。

在Swift4中关于Array:

  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) }