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

Russell Finn rsfinn at gmail.com
Thu Mar 2 15:33:14 CST 2017


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/20170302/8842bad9/attachment.html>


More information about the swift-users mailing list