在swift中打印可变内存地址

apo*_*che 141 swift

无论如何都要[NSString stringWithFormat:@"%p", myVar]用新的快速语言模拟代码?

例如:

let str = "A String"
println(" str value \(str) has address: ?")
Run Code Online (Sandbox Code Playgroud)

Woo*_*ock 160

Swift 4.X:

print(Unmanaged.passUnretained(someVar).toOpaque())
Run Code Online (Sandbox Code Playgroud)

打印someVar的内存地址.(感谢@Ying)


Swift 3.1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Run Code Online (Sandbox Code Playgroud)

打印someVar的内存地址.


  • 从 Swift 4 开始,我也能够打印这个咒语 - `Unmanagement.passUnretained(someVar).toOpaque()`(不需要通用规范) (3认同)
  • Swift 4 的答案是完美的。如果您还想在不打印的情况下获得字符串表示,我建议在其末尾添加 `debugDescription`。 (3认同)
  • Xcode 8.2.1自动更正告诉我现在是`print(Unmanaged &lt;AnyObject&gt; .passUnretained(someVar as AnyObject).toOpaque())` (2认同)
  • 只有当 someVar 是一个对象时,这才成立。如果 someVar 恰好是一个值类型,例如结构体,这将在每次执行时给出不同的地址。 (2认同)
  • @OutOnAWeekend你是对的,很可能是因为结构在作为参数传递时被复制了.使用`Unmanaged`它可以这样做:`print(Unmanaged <AnyObject> .fromOpaque(&myStruct).toOpaque())`. (2认同)

Dre*_*rew 104

斯威夫特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
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

对于Swift 3,请使用withUnsafePointer:

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

  • 如果我想用Swift 3打印**immutable**值的地址怎么办?`withUnsafePointer`导致`无法将不可变值作为inout argument`错误传递. (28认同)
  • 即使它被接受并且得到最高投票答案,它仍然会给出错误的**结果.示例:`print(self.description)`打印`<MyViewController:0x101c1d580>`,我们将其用作参考.`var mutableSelf = self; withUnsafePointer(to:&mutableSelf){print(String(format:"%p",$ 0))}`打印`0x16fde4028`,这是明显不同的地址.谁能解释为什么? (12认同)
  • @nyg你的回答给了我一个实际错误原因的线索:`UnsafePointer`是一个结构,所以为了打印_指向它的地址_(而不是结构本身)你必须打印`String(格式:"%p ",$ 0.pointee)`! (7认同)
  • 顺便说一句,这按预期打印`0x101c1d580`:`print(String(format:"%p",unsafeBitCast(self,to:Int.self))) (4认同)
  • unsafeAddressOf()仅适用于类类型(如下面的@Nick所述).因此,只有在导入Foundation并将String桥接到NSString时,此答案才有效.在普通的Swift中,String是一个值类型,unsafeAddressOf不能用于获取其地址(尝试导致编译错误). (2认同)
  • 打印的地址和调试器地址不匹配。我认为`withUnsafePointer` 返回保存要打印地址的对象的变量的指针地址。看这里 /sf/answers/2916676521/ (2认同)

Lom*_*baX 50

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

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

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

所以你的问题的答案是:

println(" str value \(str) has address: \(unsafeAddressOf(str))")
Run Code Online (Sandbox Code Playgroud)

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

斯威夫特"隐藏"指针,但它们仍然存在于引擎盖下.(因为运行时需要它,并且出于与Objc和C的兼容性原因)

但是要知道的事情很少,但首先如何打印Swift String的内存地址?

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

这将打印字符串的内存地址,如果打开XCode - > Debug Workflow - > View Memory并转到打印地址,您将看到该字符串的原始数据.由于这是一个字符串文字,因此这是二进制文件存储区内的内存地址(不是堆栈或堆).

但是,如果你这样做

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

    // example printed address 0x103f30020
Run Code Online (Sandbox Code Playgroud)

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

注意:.core._baseAddress没有记录,我发现它在变量检查器中查找,它可能在将来隐藏

_baseAddress并非适用于所有类型,此处是CInt的另一个示例

    var testNumber : CInt = 289
    takesInt(&testNumber)
Run Code Online (Sandbox Code Playgroud)

这样takesInt的C辅助函数在哪里

void takesInt(int *intptr)
{
    printf("%p", intptr);
}
Run Code Online (Sandbox Code Playgroud)

在Swift方面,这个函数是takesInt(intptr: CMutablePointer<CInt>),所以它需要CMutablePointer到CInt,你可以使用&varname获取它

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

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

swift中的字符串是原始类型,而不是对象.
CInt是映射到C int Type的Swift类型.
如果你想要一个对象的内存地址,你必须做一些不同的事情.
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
Run Code Online (Sandbox Code Playgroud)

printptr 是我用这个实现创建的C辅助函数

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)
Run Code Online (Sandbox Code Playgroud)

或者,与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
Run Code Online (Sandbox Code Playgroud)


nsc*_*hum 19

获取对象的(堆)地址

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

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

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

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

o是对实例的引用.因此,如果o分配给另一个变量o2,则返回的地址o2将是相同的.

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

获取结构的(堆栈)地址,内置类型或对象引用

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
Run Code Online (Sandbox Code Playgroud)

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

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

它是如何组合在一起的(指针回顾)

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

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

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0
Run Code Online (Sandbox Code Playgroud)

因此,除了字符串是结构体之外,这在内部这几乎与(Objective-)C中的相同.

(截至Xcode 6.3的当前版本)


nyg*_*nyg 18

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
*/
Run Code Online (Sandbox Code Playgroud)

(要点)


在Swift中,我们处理值类型(结构)或引用类型(类).做的时候:

let n = 42 // Int is a structure, i.e. value type
Run Code Online (Sandbox Code Playgroud)

一些内存在地址X分配,在这个地址我们将找到值42. Doing &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
Run Code Online (Sandbox Code Playgroud)

做的时候:

class C { var foo = 42, bar = 84 }
var c = C()
Run Code Online (Sandbox Code Playgroud)

内存分配在两个地方:

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

如上所述,类是引用类型:因此值c位于地址X,在此处我们将找到Y的值.在地址Y + 16处,我们将找到foo并且在地址Y + 24处我们将找到bar(在+ 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
Run Code Online (Sandbox Code Playgroud)

0x2a是42(foo)并且0x54是84(bar).

在这两种情况下,使用&n&c将给我们地址X.对于值类型,这是我们想要的,但不是参考类型.

做的时候:

let referencePointer = UnsafeMutablePointer<C>(&c)
Run Code Online (Sandbox Code Playgroud)

我们在引用上创建一个指针,即指向地址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)
Run Code Online (Sandbox Code Playgroud)

现在我们已经更好地理解了底层的内容,现在我们在地址X处找到地址Y(我们想要的地址),我们可以执行以下操作来获取它:

let addressY = unsafeBitCast(c, to: Int.self)
Run Code Online (Sandbox Code Playgroud)

验证:

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

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

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

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

我希望这有帮助......它对我有用.


use*_*037 12

参考类型:

  • 获取引用类型的内存地址是有意义的,因为它代表了身份.
  • === identity运算符用于检查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
Run Code Online (Sandbox Code Playgroud)

价值类型:

  • 获取值类型的内存地址的需要没有多大意义(因为它是一个值),并且重点将更多地放在值的相等性上.


Ben*_*ero 8

如果你只是想在调试器中看到这个而不用它做任何其他事情,那么就没有必要实际获得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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...
Run Code Online (Sandbox Code Playgroud)

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

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


neo*_*eye 8

斯威夫特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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

print("nil: \(String.pointer(nil))")
// nil: nil
Run Code Online (Sandbox Code Playgroud)


小智 8

只要用这个:

print(String(format: "%p", object))
Run Code Online (Sandbox Code Playgroud)

  • 它需要在“CVarArg”上实现“var _cVarArgEncoding: [Int]”。不清楚应该如何实施。 (2认同)

Nic*_*len 6

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

但是,如果您使用第二种方法获取具有值类型元素的数组的地址。Swift 将复制整个数组,因为在 Swift 中数组是写时复制的,并且一旦将控制权传递给 C/C++(通过使用&获取地址触发),Swift 就无法确保它的行为方式。如果你改用第一种方法,它会自动转换ArrayNSArray我们不想要的东西。

所以我找到的最简单和统一的方法是使用 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
}
Run Code Online (Sandbox Code Playgroud)


Sen*_*nKe 6

在关于数组的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)
    }
Run Code Online (Sandbox Code Playgroud)


Cha*_*roe 5

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

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

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int
Run Code Online (Sandbox Code Playgroud)

只是一点点跟进。


EvG*_*yin 5

我在 Swift 3 上的解决方案

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

此代码创建描述,如默认描述 <MyClass: 0x610000223340>