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

时间:2014-06-10 16:41:27

标签: c macos pointers struct swift

我知道this answer,但这不是一回事 - 那就是传递一个指针,并通过分配进行初始化。

我与具有以下结构定义的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<myStruct>)

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

Swift目前也不支持固定大小的阵列。

我无法看到如何满足结构的初始化,或者让Swift认为通过电话会这样做。

任何帮助都非常感谢!

6 个答案:

答案 0 :(得分:11)

首先,让我们定义用于测试的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<my_struct>.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>() -> S {
    let struct_pointer = UnsafeMutablePointer<S>.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)

答案 1 :(得分:3)

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

C Struct as Swift Struct

在这个特殊情况下,

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

when设置为纪元。

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

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

上面的例子是:

var when = blankof(timespec)

答案 2 :(得分:3)

从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
    }
}

答案 3 :(得分:2)

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

要在不修改原始C库的情况下解决该问题,我在Bridging.c / .h中创建了创建/销毁函数

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<myStruct> = CreateMyStruct();
DoSomething(mine);
DestroyMyStruct(&mine);

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

答案 4 :(得分:1)

这个怎么样

var mine : UnsafePointer<myStruct> = nil
initMyStrict(&mine)

答案 5 :(得分:0)

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

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

#include <cstdio>

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 * ...