Swift:将未初始化的C结构传递给导入的C函数

我知道这个答案 ,但这不是一回事 – 那就是传递一个指针,用分配初始化。

我正在与具有以下结构定义的C库连接:

typedef struct myStruct { unsigned char var [50]; } myStruct; 

有一个函数可以传递结构的地址 – 通常基于堆栈而不是堆,因此:

 myStruct mine; initMyStruct(&mine); 

这会初始化结构的内容 – 调用者不知道内存的内部格式,因此混淆。

在Swift中,我正在创建一个类,它将封装结构和与其上运行的其他C函数的接口。

 class MyClass { var mine : myStruct init() { initMyStruct(&mine) // Error: Variable 'self.msg' passed by reference before being initialized } } 

我不能为我的生活弄清楚如何初始化结构,或者如果可以替代使用一个点。

 mine = myStruct() // Fails because you aren't providing the value of the member 'var' mine = myStruct((CUnsignedChar(), CUnsignedChar(), /*... repeat to 50 */)) // Cannot find an overload for 'init' that accepts the arguments 

请注意,这是将已分配(基于堆栈)结构的地址传递给已导入的函数

 CInt initMyStruct(str: CMutablePointer) 

它没有传递一个由有问题的C库分配的指针,这似乎是一个更常见的要求,并在其他地方得到解答。

Swift目前也不支持固定大小的数组。

我无法看到如何满足结构的初始化或使Swift认为它将通过调用完成。

任何帮助非常感谢!

首先,让我们定义用于测试的C代码:

 typedef struct my_struct { unsigned char buffer[10]; } my_struct; void my_struct_init(my_struct *my_s) { for (int i = 0; i < 10; i++) { my_s->buffer[i] = (char) i; } } 

在Swift中,我们有两个选择:

1.堆叠上的结构

 var my_s: my_struct = ... 

但是,我们必须以某种方式初始化它。 每个结构都有一个默认初始化程序

 var my_s: my_struct = my_struct(buffer: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) 

请注意,在这种情况下, buffer[10]已被转换为Swift作为10-tuple

现在我们可以打电话:

 my_struct_init(&my_s) print("Buffer: \(my_s.buffer)") // Buffer: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 

但是,结构越复杂,使用默认初始化程序就越困难。

2.堆上的结构

这类似于在C中使用mallocfree

 var my_s_pointer = UnsafeMutablePointer.allocate(capacity: 1) print("Buffer: \(my_s.buffer)") // Buffer: (some random values) my_struct_init(my_s_pointer) print("Buffer: \(my_s_pointer.memory.buffer)") // Buffer: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) my_s_pointer.deallocate() 

结合两种方法

以下函数将初始化任何结构:

 func initStruct() -> S { let struct_pointer = UnsafeMutablePointer.allocate(capacity: 1) let struct_memory = struct_pointer.pointee struct_pointer.dealloate() return struct_memory } var my_s: my_struct = initStruct() my_struct_init(&my_s) 

信不信由你,你可以像Swift Struct一样初始化C Struct。 Xcode甚至可以为您自动填充成员名称!

C Struct as Swift Struct

在这个特殊情况下,

 var when = timespec(tv_sec:0, tv_nsec:0) 

将设置when到纪元。

这是一个神奇的初始化程序,它为您提供任何空白结构:

 func blankof(type:T.Type) -> T { var ptr = UnsafePointer.alloc(sizeof(T)) var val = ptr.memory ptr.destroy() return val } 

上面的例子是:

 var when = blankof(timespec) 

从Swift 1.2(Xcode 6.3 beta)开始,导入的C结构现在在Swift中有一个默认的初始化器,它将所有struct的字段初始化为零。

在你的情况下:

 class MyClass { var mine = myStruct() // <-- Initializes all elements to zero init() { initMyStruct(&mine) // <-- No error anymore because `mine` is initialized } } 

我对C库有同样的问题,并在Apple的论坛上提出了这个问题。 到目前为止没有决议。

为了解决这个问题而不修改原始C库,我在Bridging.c / .h中创建了Create / Destroy函数

Bridging.h

 typedef struct myStruct { unsigned char var [50]; } myStruct; myStruct * CreateMyStruct(); void DestroyMyStruct(myStruct **s); void DoSomething(myStruct *s); 

Bridging.c

 myStruct * CreateMyStruct() { myStruct * mine = malloc(sizeof(myStruct)); if (mine) initMyStruct(mine); return mine; } void DestroyMyStruct(myStruct **s) { if (*s) free(*s); *s = NULL; // set the swift variable to nil } void DoSomething(myStruct *s) { // ... } 

Example.swift

 var mine : UnsafePointer = CreateMyStruct(); DoSomething(mine); DestroyMyStruct(&mine); 

这并没有利用ARC,但它至少在没有修改原始库的情况下解决了问题。

这个怎么样

 var mine : UnsafePointer = nil initMyStrict(&mine) 

我不知道initMyStruct里面发生了什么……但是假设它是一个函数,它将你要复制到字符串var的字符串作为参数

我从来没有使用过swift …但是在这里的代码中你可以将你的struct作为c ++类成员…
也许你可以使用这个只封装结构的类?

 #include  typedef struct myStruct { unsigned char var [50]; } myStruct; void initMyStruct(myStruct *mine, char *ini) { int i = 0; do { mine->var[i] = (unsigned char) ini[i]; } while(ini[i++]); } class MyClass { public: myStruct st; MyClass(char *parameter) { initMyStruct(&st, parameter); } }; int main() { MyClass c("Hakuna Matata!"); printf("%s\n", c.st.var); } 

如果它使用一些cstring函数,它可能会导致一些问题,因为指针是unsigned char *而不是char * …