我正在尝试在 go 端初始化一个 C 数组结构。 我是cgo的新手。仍在尝试理解用例。
测试.h
typedef struct reply {
char *name;
reply_cb callback_fn;
} reply_t;
typedef struct common {
char *name;
int count;
reply_t reply[];
} common_t;
int
init_s (common_t *service);
测试.go
name := C.CString("ABCD")
defer C.free(unsafe.Pointer(name))
num := C.int(3)
r := [3]C.reply_t{{C.CString("AB"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("BC"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("CD"), (C.s_cb)(unsafe.Pointer(C.g_cb))}}
g := C.common_t{
name: name,
count: num,
reply : r,
}
rc := C.init_s(&g)
我在“回复:r”类型的结构文字中的未知字段“r”上收到错误
任何帮助将不胜感激。目标是初始化,然后在 C init_s 中使用它的值进行处理。
最佳答案
您不能使用 Go 中的灵活数组字段:https://go-review.googlesource.com/c/go/+/12864/ .
我认为原因很简单:C 的这个缺点通常要求您执行一个技巧,分配一个适当对齐的内存缓冲区,足够长以容纳开始时的 sizeof(struct_type)
本身该缓冲区加上 sizeof(array_member[0]) * array_element_count
字节。这不会映射到 Go 的类型系统,因为在其中,结构具有在编译时已知的固定大小。如果 Go 不从定义中隐藏 reply
,它将引用一个零长度的字段,您无论如何都不能做任何有用的事情——参见 #20275 .
不要被灵活数组成员字段用文字初始化的代码示例所欺骗:as torek指出,它是一个 GCC 扩展,但更重要的是,它需要编译器的一部分工作——也就是说,它分析文字,理解它出现的上下文并生成一个代码,该代码分配足够大的内存块来容纳两者灵活数组的结构和所有成员。
你的 Go 代码中数组的初始化表面上看起来很相似,但它有一个重要的区别:它分配了一个单独的数组,它与它应该被“放置”的结构的内存块无关进入”。
更重要的是,Go 的数组与 C 的不同:在 C 中,数组是变相的指针,在 Go 中,数组是一等公民,当您分配数组或将其传递给函数调用时,整个数组按值复制——而不是“退化为指针”——用 C 的术语来说。
因此,即使 Go 编译器不会隐藏 reply
字段,对其赋值也会失败。
我认为如果没有用 C 编写的额外辅助代码,你不能直接使用 Go 中的这种类型的值。例如,要初始化 common_t
的值,你可以编写一个 C 辅助程序,它首先分配一个足够长的内存缓冲区,然后向 Go 代码公开一对指针:指向缓冲区的开头(类型为 *C.common_t
),以及指向数组的第一个元素——如 *C.reply_t
.
如果此 C 代码是您自己的代码,我建议您去掉灵活数组并在 reply
字段中保留一个指向“普通”数组的指针。
是的,这将意味着 CPU 需要额外的指针追逐,但与 Go 的互操作性会更简单。
关于c - 从 Go 初始化灵活数组 C 结构成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73655587/