c - 从 Go 初始化灵活数组 C 结构成员

标签 c go cgo

我正在尝试在 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/

相关文章:

c - 检测写入数据的偏移量

c++ - Arduino - 预期的不合格 ID

java - 如何从 cgo 返回的 C 字符串中释放 java 中的内存(使用 jna)?

go - 什么是 cgo 类型,相当于指向结构的 const 指针?

c - 如何计算两个数字之间的差异

包含函数指针的 c 结构

go build 在编译 cgo 包时找不到我的 C 标准库

go - 为 CI 服务器推荐的 Go 构建系统?

unit-testing - 如何比较两个作为结构但作为接口(interface)返回的值

go - 从共享库访问函数时出现内存不足 panic