Swift 取得變數的 Pointer/Address == # 工具 * `withUnsafePointer(to:)` [Doc](https://developer.apple.com/documentation/swift/2431879-withunsafepointer) > `func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result` > * `withUnsafePointer(to:_:)` [Doc](https://developer.apple.com/documentation/swift/2429788-withunsafemutablepointer) > `func withUnsafeMutablePointer<T, Result>(to value: inout T, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result` * `Array<T>::withUnsafeBufferPointer(_:)` [Doc](https://developer.apple.com/documentation/swift/array/2994771-withunsafebufferpointer) > `func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R` * Swift Compiler's implicit bridge for Array # Single Variable * `withUnsafeMutablePointer` has `inout` in first parameter, it need leading `&` when passing ``` var x = 1 withUnsafePointer(to: x) { ptr in print(type(of: ptr)) print(ptr.pointee) } withUnsafeMutablePointer(to: &x) { ptr in print(type(of: ptr)) print(ptr.pointee) } func seeAddr<T>(_ ptr: UnsafePointer<T>) { print(type(of: ptr)) print(ptr.pointee) } seeAddr(&x) ``` ## Output ``` UnsafePointer<Int> 1 UnsafeMutablePointer<Int> 1 UnsafePointer<Int> 1 ``` # Array > * need use inout syntax(&) for `withUnsafeMutablePointer` > * `withUnsafePointer` is used to get `Array<T>` instead of `T` in `Array` > * To extract `T` from `Array<T>`, need to use `Array<T>`'s method `withUnsafeBufferPointer` ``` var a = [1,2,3] // withUnsafePointer(to: T, (UnsafePointer->Result)) -> Result withUnsafePointer(to: a) { ptr in print(type(of: ptr)) } // withUnsafeMutablePointer(to: inout T, (UnsafeMutablePointer->Result)) -> Result withUnsafeMutablePointer(to: &a) { ptr in print(type(of: ptr)) } // Array<T>::withUnsafeBufferPointer((UnsafeBufferPointer->Result)) -> Result a.withUnsafeBufferPointer { ptr in print(type(of: ptr)) } ``` ## Output ``` UnsafePointer<Array<Int>> UnsafeMutablePointer<Array<Int>> UnsafeBufferPointer<Int> ``` # Get address as `UnsafePointer<T>` from Array > `withUnsafePointer` seems is unable to get correct address ``` var a = [2,3,5] withUnsafePointer(to: a[0]) { ptr in print(type(of: ptr)) print(ptr[0]) // print 1 print(ptr[1]) // still print 1, it seems ptr does not point to the original one } withUnsafeMutablePointer(to: &a[0]) { ptr in print(type(of: ptr)) print(ptr[0]) print(ptr[1]) print(ptr[2]) } a.withUnsafeBufferPointer{ ptr in print(type(of: ptr)) print(ptr[0]) print(ptr[1]) print(ptr[2]) let addrOpt = ptr.baseAddress print(type(of: addrOpt)) let addr = addrOpt! print(type(of: addr)) print(addr[0]) print(addr[1]) print(addr[2]) } ``` ## Output ``` UnsafePointer<Int> 2 2 UnsafeMutablePointer<Int> 2 3 5 UnsafeBufferPointer<Int> 2 3 5 Optional<UnsafePointer<Int>> UnsafePointer<Int> 2 3 5 ``` # Implicit Bridge Array to `UnsafePointer<T>` when passing as function parameter ::: warning According to https://developer.apple.com/documentation/swift/unsafepointer > The pointer created through implicit bridging of an instance or of an array’s elements is only valid during the execution of the called function. Escaping the pointer to use after the execution of the function is undefined behavior. In particular, do not use implicit bridging when calling an UnsafePointer initializer. ``` var number = 5 let numberPointer = UnsafePointer<Int>(&number) // Accessing 'numberPointer' is undefined behavior. ``` ::: ``` var a = [2,3,5] func seeAddr<T>(_ ptr: UnsafePointer<T>) { print(ptr[0]) print(ptr[1]) print(ptr[2]) } print("implicit bridge Array to UnsafePointer<T>") seeAddr(a) // implicit bridge Array<T> to UnsafePointer<T> print("implicit bridge Array with inout syntax(&) to UnsafePointer<T>") seeAddr(&a) // implicit bridge Array<T> with inout syntax to UnsafePointer<T> ``` ## Output ``` implicit bridge Array to UnsafePointer<T> 2 3 5 implicit bridge Array with inout syntax(&) to UnsafePointer<T> 2 3 5 ``` # Reference * [UnsafePointer](https://developer.apple.com/documentation/swift/unsafepointer)