[英]Swift - Difference between passing variable and passing variable address withUnsafePointer?
最近我试图查看我的变量的地址,但我有这个问题。
var age: Int = 5
withUnsafePointer(to: age) {
print($0) // 0x00007ffee3362750
print($0.pointee) // 5
}
withUnsafePointer(to: &age) {
print($0) // 0x000000010d226330
print($0.pointee) // 5
}
为什么它显示不同的 memory 地址以及为什么它为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 显示相同的 memory 地址,为什么当我传递 memory 地址时它为索引 1 和 2 显示不同的 memory 地址?
感谢您的回答并期待了解这一点
您看到的不同之处在于您使用了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
两者之间的区别在于用于value
参数的inout
限定符。
现在,让我们尝试了解幕后发生的事情。
首先, 0x00007ffee3362750
看起来像一个堆栈指针,而0x000000010d226330
看起来像一个堆指针。 堆栈地址从为程序分配的 memory 的顶部开始,并随着每次 function 调用而减少(并在 function 返回时增加)。
这表明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)
}
因此,第一个调用需要分配一个中间位置 memory,这就是您看到两个不同地址的原因,这是因为地址没有指向相同的 memory 位置。 但是,由于两个 memory 位置都以相同的值开始,因此打印指向pointee
会得到相同的 output。
现在,让我们谈谈数组示例。 您看到的行为具有相同的原因:堆栈分配。 发生的事情是:
withUnsafePointer
被调用,这是一个function的调用,栈是为function预留的; 堆栈指针是 P - NwithUnsafePointer
创建临时可写变量,并执行withUnsafePointer
返回,并释放堆栈 memory,此时堆栈指针回到 PwithUnsafePointer
时,堆栈指针返回 P - N,但是由于两者之间没有其他 function 调用,因此为临时可写变量保留了相同的堆栈地址,因此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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.