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

Dav*_*han 13 c macos struct pointers swift

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

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

typedef struct myStruct { unsigned char var [50]; } myStruct;
Run Code Online (Sandbox Code Playgroud)

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

myStruct mine;
initMyStruct(&mine);
Run Code Online (Sandbox Code Playgroud)

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

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

class MyClass {

    var mine : myStruct

    init() {

        initMyStruct(&mine)
        // Error: Variable 'self.msg' passed by reference before being initialized

    }

}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

CInt initMyStruct(str: CMutablePointer<myStruct>)
Run Code Online (Sandbox Code Playgroud)

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

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

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

任何帮助非常感谢!

Sul*_*han 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

1.堆叠上的结构

var my_s: my_struct = ...
Run Code Online (Sandbox Code Playgroud)

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

var my_s: my_struct = my_struct(buffer: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
Run Code Online (Sandbox Code Playgroud)

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

现在我们可以致电:

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

但是,结构越复杂,使用默认初始值设定项就越困难.

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()
Run Code Online (Sandbox Code Playgroud)

结合两种方法

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

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)
Run Code Online (Sandbox Code Playgroud)


nig*_*ade 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);
}
Run Code Online (Sandbox Code Playgroud)

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