最近我试图查看我的变量的地址,但我有这个问题。
var age: Int = 5
withUnsafePointer(to: age) {
print($0) // 0x00007ffee3362750
print($0.pointee) // 5
}
withUnsafePointer(to: &age) {
print($0) // 0x000000010d226330
print($0.pointee) // 5
}
为什么它显示不同的内存地址以及为什么它为 pointee
显示相同的值?
var strarr = [1, 2]
withUnsafePointer(to: strarr[0]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 1
}
withUnsafePointer(to: strarr[1]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 2
}
withUnsafePointer(to: &strarr[0]) {
print("\($0)") // 0x0000600002755760
print("\($0.pointee)") // 1
}
withUnsafePointer(to: &strarr[1]) {
print("\($0)") // 0x0000600002755768
print("\($0.pointee)") // 2
}
对于数组,为什么当我没有传递变量地址时它为索引 1 和 2 显示相同的内存地址,为什么当我传递变量地址时它为索引 1 和 2 显示不同的内存地址内存地址?
感谢您的回答并期待了解这一点
最佳答案
您看到的不同之处在于您使用了 withUnsafePointer
的两个不同重载,我将按照您使用它们的相同顺序列出它们:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
和
func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
两者的区别在于 inout
用于 value
参数的限定符。
现在,让我们尝试了解幕后发生的事情。
首先,0x00007ffee3362750
看起来像一个栈指针,而 0x000000010d226330
看起来像一个堆指针。堆栈地址从为程序分配的内存的顶部开始,并随着每次函数调用而减少(并在函数返回时增加)。
这表明 withUnsafePointer
的第一个重载从作为参数传递的变量创建了一个临时的可写变量。这是必需的,因为 UnsafePointer
需要一个 inout
引用才能使用,并且常规参数是只读的。
这意味着 withUnsafePointer
的非 inout 重载的实现看起来像这样:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result {
var value = value // shadow the argument, create a readwrite location
return try withUnsafePointer(&value, body)
}
因此,第一个调用需要分配一个中间内存位置,这就是为什么您会看到两个不同的地址,因为地址没有指向同一个内存位置。但是,由于两个内存位置都以相同的值开始,因此打印 pointee
会产生相同的输出。
现在,让我们谈谈数组示例。您看到的行为具有相同的原因:堆栈分配。发生的事情是:
- 程序开始执行,栈指针的值为P(随机名)
- non-inout
withUnsafePointer
被调用,这是一个函数调用,栈是为函数预留的;堆栈指针为 P - N withUnsafePointer
创建临时可写变量,并执行withUnsafePointer
返回,并释放栈内存,此时栈指针回到P- 第二个非inout
withUnsafePointer
被调用,栈指针回到P - N,但是由于两者之间没有其他函数调用,相同的栈地址被保留给临时可写变量,因此UnsafePointer
实例具有相同的地址
这里,即使UnsafePointer
指向同一个地址,该地址的值也是不同的,分别对应arr[0]
和arr的值[1]
.
对于 inout 调用,UnsafePointer
指向数组缓冲区中项目的实际地址。
这也是您可以为非 inout 调用获取不同值的方法:
withUnsafePointer(to: strarr[0]) {
print("\($0)")
print("\($0.pointee)")
}
// this adds a nested function call, which also decreases the stack pointer
// resulting in the temporary location not being on the same stack address
func test() {
withUnsafePointer(to: strarr[1]) {
print("\($0)")
print("\($0.pointee)")
}
}
test()
关于ios - Swift - 使用UnsafePointer传递变量和传递变量地址之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64841775/