我有一个Swift程序,可以与C库互操作。这个C库返回一个内部带有char[]数组的结构,如下所示:

struct record
{
    char name[8];
};

该定义已正确导入到Swift中。但是,该字段被解释为8个Int8元素(类型为(Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8))的元组,我不知道如何使用Swift将其转换为String

没有String初始化程序接受Int8元组,并且似乎不可能获得指向元组的第一个元素的指针(因为类型可以是异构的,这并不奇怪)。

现在,我最好的主意是创建一个微型C函数,该函数接受指向结构本身的指针,并返回name作为char*指针而不是数组,然后进行操作。

但是,那里有纯粹的Swift方法吗?

最佳答案

C数组char name[8]作为元组导入到Swift:

(Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
name的地址与name[0]的地址相同,并且
Swift 保留从C导入的结构的内存布局,如下
confirmed by Apple engineer Joe Groff:

因此,我们可以传递record.name的地址,
转换为UInt8指针,以
字符串初始化器。以下代码已针对 Swift 4.2 及更高版本进行了更新:
let record = someFunctionReturningAStructRecord()
let name = withUnsafePointer(to: record.name) {
    $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
        String(cString: $0)
    }
}
注意:假定name[]中的字节是有效的NUL终止的UTF-8序列。
对于旧版的Swift:
// Swift 2:
var record = someFunctionReturningAStructRecord()
let name = withUnsafePointer(&record.name) {
    String.fromCString(UnsafePointer($0))!
}

// Swift 3:
var record = someFunctionReturningAStructRecord()
let name = withUnsafePointer(to: &record.name) {
    $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: record.name)) {
        String(cString: $0)
    }
}

10-04 17:57