[swift-users] Using withUnsafePointer on char arrays within C structs

Russell Finn rsfinn at gmail.com
Fri Mar 3 10:24:40 CST 2017


Ahh ... which is exactly implied by the documentation I quoted, except that
I'm so used to doing it the other way (with `var` and `&`) that I failed to
interpret what the text was saying.  Thanks for the tip.

On Thu, Mar 2, 2017 at 4:43 PM, Hooman Mehr <hooman at mac.com> wrote:

> Yes, the easiest way is to rely on compiler magic for ObjC/C
> interoperability, but it is also important to know what is really happening.
>
> My preferred version of the compiler magic is this actually:
>
> func allZerosUUID() -> String {
>
>     return NSUUID(uuidBytes: [UInt8](repeating: 0, count: 32)).uuidString
> }
>
> Which is effectively this:
>
> func allZerosUUID() -> String {
>
>     let allZeros = [UInt8](repeating: 0, count: 32)
>
>     return NSUUID(uuidBytes: allZeros).uuidString
> }
>
> (Note the use of let and absence of &).
>
> On Mar 2, 2017, at 1:33 PM, Russell Finn <rsfinn at gmail.com> wrote:
>
> I agree that the use of `withUnsafeBufferPointer` to get to the contents
> of an array makes more sense than `withUnsafePointer`, once you discover
> the concept of a "buffer pointer" (which a new Swift programmer may not do
> at first).
>
> However, I note that the following code:
>
>     func allZerosUUID() -> String {
>         var allZeros = [UInt8](repeating: 0, count: 32)
>         return NSUUID(uuidBytes: &allZeros)
>     }
>
> also compiles without error and returns the intended value. This appears
> to be supported by the "Constant Pointers" section of the "Interacting with
> C APIs" chapter of "Using Swift with Cocoa and Objective-C":  "When a
> function is declared as taking an `UnsafePointer<Type>` argument, it can
> accept ... a `[Type]` value, which is passed as a pointer to the start of
> the array."
>
> I suspect the availability of `&array` in this context, coupled with an
> awareness of the existence of `withUnsafePointer(to:)`, is what led my
> co-worker down the wrong road (and to a puzzling error message); but since
> we have now discovered two more appropriate ways to write the code in
> question, perhaps it's not worth worrying about too much.
>
> Thanks to everyone for the discussion.
>
>
> On Wed, Mar 1, 2017 at 7:36 PM, Hooman Mehr <hooman at mac.com> wrote:
>
>> Your co-worker needs to get passed the learning curve of these “unsafe”
>> APIs and note that Swift arrays are complex data structures. &allZeros does
>> not give you a pointer to a bunch of zero bytes, but a pointer to a struct
>> that contains the private implementation details of allZeros array.
>>
>> Here is the correct way to do it:
>>
>> func allZerosUUID() -> String {
>>
>>     let allZeros = [UInt8](repeating: 0, count: 32)
>>
>>     return allZeros.withUnsafeBufferPointer { NSUUID(uuidBytes: $0.
>> baseAddress).uuidString }
>> }
>>
>>
>> On Mar 1, 2017, at 2:35 PM, Russell Finn via swift-users <
>> swift-users at swift.org> wrote:
>>
>> Thanks to Joe and Quinn for their answers. I have a related followup — a
>> co-worker learning Swift wrote the following function:
>>
>>     func allZerosUUID() -> String {
>>         var allZeros = [UInt8](repeating: 0, count: 32)
>>         return withUnsafePointer(to: &allZeros) { zerosPtr in
>>             return NSUUID(uuidBytes: zerosPtr).uuidString
>>         }
>>     }
>>
>> but was puzzled that Xcode 8.2.1 gave an error "Cannot convert value of
>> type 'UnsafePointer<_>' to expected argument type 'UnsafePointer<UInt8>!'"
>> on the line with the NSUUID initializer.  Their expectation was that
>> `zerosPtr` would be of type `UnsafePointer<UInt8>` because `allZeros` is of
>> type `[UInt8]`.
>>
>> They discovered that they could work around this by adding a call to
>> `withMemoryRebound`:
>>
>>     func allZerosUUID() -> String {
>>         var allZeros = [UInt8](repeating: 0, count: 32)
>>         return withUnsafePointer(to: &allZeros) { zerosPtr in
>>             zerosPtr.withMemoryRebound(to: UInt8.self, capacity:
>> allZeros.count) { zerosPtr in
>>                 return NSUUID(uuidBytes: zerosPtr).uuidString
>>             }
>>         }
>>     }
>>
>> but felt that this should be unnecessary. Perhaps I'm missing something
>> simple, but I was unable to explain this compiler behavior; can anyone on
>> the list do so?
>>
>> (Yes, I did point out that they could pass `&allZeros` directly to
>> `NSUUID(uuidBytes:)`.)
>>
>> Thanks — Russell
>>
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170303/0687fb66/attachment.html>


More information about the swift-users mailing list