import Foundation
func address(o:UnsafeRawPointer) -> Int {
return Int(bitPattern: o)
}
var originArray = [1,2,3]
var firstArray = originArray
//q.append(4)
print(NSString.init(format: "originArray:%p", address(o: &originArray)))
print(NSString.init(format: "firstArray:%p", address(o: &firstArray)))
调试日志: originArray:0x100b087b0 firstArray:0x100b088c0
上面,这是我的测试代码。我认为我不修改originArray,就像追加或减少元素一样。他们应该指出相同的地址。但为什么要尊重
答案 0 :(得分:3)
您的代码在将值传递给指针参数时打印数组缓冲区的地址(Array
is a special case。但是,在Swift 3中,编译器假定&
运算符的存在意味着缓冲区作为可变内存传递,因此(不必要地)使其成为唯一(通过复制)之前传递其指针值,尽管指针值作为UnsafeRawPointer
传递。这就是你看到不同地址的原因。
如果删除&
运算符并直接传递数组:
func address(_ p: UnsafeRawPointer) {
print(p)
}
var originArray = [1, 2, 3]
var firstArray = originArray
address(originArray) // 0x00000000016e71c0
address(firstArray) // 0x00000000016e71c0
您现在将获得相同的地址,因为编译器现在假定address(_:)
不会修改传递的缓冲区的内存,因为它们被传递给UnsafeRawPointer
参数。
在Swift 4中,这种不一致性是固定的,并且编译器在将指针值传递给UnsafeRawPointer
参数之前不再使缓冲区唯一,即使使用&
运算符,所以代码展示预期的行为。
虽然,值得注意的是,当将相同的数组传递给多个指针参数时,上述方法不能保证产生稳定的指针值。
来自Swift博客文章“Interacting with C Pointers”:
即使您将相同的变量,数组或字符串作为多个指针参数传递,每次都可以接收不同的指针。
我相信这种保证在两种情况下都不能满足(可能还有更多):
如果数组正在查看非连续存储中的元素
Swift的Array
可以查看非连续存储中的元素,例如当它包装NSArray
时。在这种情况下,当将其传递给指针参数时,必须创建 new 连续缓冲区,从而为您提供不同的指针值。
如果缓冲区作为可变内存传递时是非唯一引用的
如前所述,当将数组传递给可变指针参数时,其缓冲区将首先变为唯一,以保留值语义,因为假设该函数将执行缓冲区的变异。
因此,如果复制了缓冲区,如果已将数组传递给不可变指针参数,则会获得不同的指针值。
虽然这两个点都不适用于你给出的例子,但值得记住的是,当传递给指针参数时,编译器仍然不保证指向数组缓冲区的稳定指针值
对于保证可靠的结果,您应该在withUnsafeBytes(_:)
上使用ContiguousArray
方法:
var originArray: ContiguousArray = [1, 2, 3]
var firstArray = originArray
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000102829550
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000102829550
这是因为withUnsafeBytes(_:)
被记录为接受:
带有
UnsafeRawBufferPointer
参数的闭包,指向数组的连续存储。如果不存在此类存储,则会创建它。
[it]始终将其元素存储在连续的内存区域
就像Array
一样,ContiguousArray
使用copy-on-write以获得值语义,因此您仍然可以使用它来检查何时在发生突变时复制数组的缓冲区:
var originArray: ContiguousArray = [1, 2, 3]
var firstArray = originArray
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray[0] = 4
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000100e764d0
答案 1 :(得分:1)
您正在打印变量本身的地址,而不是它所指向的数组缓冲区的地址。
您可以像这样获取数组缓冲区的地址:
var originArray = [1, 2, 3]
var firstArray = originArray
print("originArray: \(originArray.withUnsafeBytes { $0.baseAddress! })")
print("firstArray: \(firstArray.withUnsafeBytes { $0.baseAddress! })")
现在打印相同的值,除非您修改其中一个数组。