将Swift uuid_t传递给C函数

时间:2017-07-24 23:45:30

标签: swift swift3 uuid bridging-header

使用Swift,如何将UUID传递给带有uuid_t的C函数?

假设我在桥接标题中声明了以下函数:

bool my_set_uuid(uuid_t uuid);

在Swift中,我试图传递一个新的UUID:

let uuid = UUID()
my_set_uuid(uuid.uuid)

我收到以下错误:“无法转换类型'uuid_t'(又名'(UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8, UInt8,UInt8)')预期的参数类型'UnsafeMutablePointer!'“

我知道这是因为UUID.uuid的类型为uuid_t,它实现为16字节的C数组,在Swift中成为16个UInt8的元组。但为什么我不能将C uuid_t传递给C?它似乎在期待一个指针。

所以,我尝试用withUnsafeMutableBytes创建指向我的uuid的指针。我发现这很有效:

let _: UInt8 = withUnsafeMutablePointer(to: &uuid.0) { ptr in
    my_set_uuid(ptr)
    return 0
}

但是我也读过& uuid.0是不安全的,因为我在我的C函数中使用了整个元组(作为一个数组)。此外,我与let _: UInt8return 0所做的所有装扮似乎都是错误的。

2 个答案:

答案 0 :(得分:2)

以这种方式使用&uuid.0确实不安全。由于Swift编译器可以在临时区域中创建单个元素的副本,并将该区域的地址传递给该函数。这可能不会在优化代码中发生,但您无法预测Swift生成的代码。

为了使您的代码安全,您可能需要编写如下内容:

    let uuid = UUID()
    var rawUuid = uuid.uuid
    // (You can rewrite the two lines above into a sigle line as `var rawUuid = UUID().uuid`
    let result = withUnsafeMutablePointer(to: &rawUuid) {uuidPtr in
        uuidPtr.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<uuid_t>.size) {bytePtr in
            my_set_uuid(bytePtr)
        }
    }

result获取my_set_uuid(bytePtr)的值。如果您想忽略该结果,请将let result替换为_。)

uuid_t是C中固定大小的数组类型,这在Swift中很难处理。也许Swift中的元组类型应该有更好的方法来处理这种用例。

答案 1 :(得分:-1)

你可以试试这个:

    let uuid = UUID().uuidString        
    _ = uuid.withCString { s1 in
        my_set_uuid(UnsafeMutablePointer(mutating: s1))
    }