简体   繁体   English

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

[英]Initialize flexible array C struct member from Go

I am trying to initialize a struct of C array in go side.我正在尝试在 go 端初始化 C 数组的结构。 I am new to cgo.我是cgo的新手。 Still trying to understand the use case.仍在尝试了解用例。

test.h测试.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);


test.go测试.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)

I am getting error on "reply: r" unknown field 'r' in struct literal of type我在类型结构文字中的“回复:r”未知字段“r”上收到错误

Any help will be appreciated.任何帮助将不胜感激。 The goal is initialize and then use it values in C init_s for processing.目标是初始化,然后在 C init_s 中使用它的值进行处理。

You cannot use a flexible array field from Go: https://go-review.googlesource.com/c/go/+/12864/ .您不能使用 Go 中的灵活数组字段: https://go-review.googlesource.com/c/go/+/12864/

I think the reasonong is simple: this wart of C normally requires you to perform a trick of allocating a properly-aligned memory buffer long enough to accomodate for the sizeof(struct_type) itself at the beginning of that buffer plus sizeof(array_member[0]) * array_element_count bytes.我认为原因很简单:C 的这个缺陷通常需要您执行一个技巧,即分配一个正确对齐的 memory 缓冲区,其长度足以容纳该缓冲区开头的sizeof(struct_type)本身加上sizeof(array_member[0]) * array_element_count个字节。 This does not map to Go's type system because in it, structs have fixed size known at compile time.这不适用于 Go 的类型系统,因为在其中,结构具有在编译时已知的固定大小。 If Go would not hide reply from the definition, it would refer to a zero-length field you cannot do anything useful with anyway—see #20275 .如果 Go 不会从定义中隐藏reply ,则它将引用一个零长度字段,无论如何您都无法做任何有用的事情 - 请参阅#20275

Don't be deceived by code examples where a flexible array member field is initialized with a literal: as torek pointed out, it's a GCC extension, but what is more important, it requires work on part of the compiler—that is, it analyzes the literal, understands the context it appeared in and generates a code which allocates large enough memory block to accomodate both the struct and all the members of the flexible array.不要被使用文字初始化灵活数组成员字段的代码示例所欺骗:正如torek指出的那样,它是 GCC 扩展,但更重要的是,它需要编译器的一部分工作——也就是说,它分析文字,理解它出现的上下文并生成一个代码,该代码分配足够大的 memory 块以容纳结构和灵活数组的所有成员。
The initialization of the array in your Go code may look superficially similar but it has an important difference: it allocates a separate array which has nothing to do with the memory block of the struct it's supposed to be "put into". Go 代码中数组的初始化可能看起来很相似,但它有一个重要的区别:它分配了一个单独的数组,与它应该“放入”的结构的 memory 块无关。
What's more Go's array are different beasts than C's: in C, arrays are pointers in disguise, in Go, arrays are first-class citizens and when you assign an array or pass it to a function call, the whole array is copied by value—as opposed to "decaying into a pointer"—in C's terms. What's more Go's array are different beasts than C's: in C, arrays are pointers in disguise, in Go, arrays are first-class citizens and when you assign an array or pass it to a function call, the whole array is copied by value—与“衰减为指针”相反——用 C 的术语来说。 So even if the Go compiler would not hide the reply field, assignment to it would fail.所以即使 Go 编译器不会隐藏reply字段,分配给它也会失败。

I think you cannot directly use values of this type from Go without additional helper code written in C.我认为如果没有用 C 编写的附加帮助代码,您不能直接使用 Go 中的这种类型的值。 For instance, to initialize values of common_t , you would write a C helper which would first allocate a memory buffer long enough and then expose to the Go code a pair of pointers: to the beginning of the buffer (of type *C.common_t ), and to the first element of the array—as *C.reply_t . For instance, to initialize values of common_t , you would write a C helper which would first allocate a memory buffer long enough and then expose to the Go code a pair of pointers: to the beginning of the buffer (of type *C.common_t ) ,以及数组的第一个元素——作为*C.reply_t

If this C code is the code you own, I'd recommend to just get rid of the flexible array and maintain a pointer to a "normal" array in the reply field.如果此 C 代码是您拥有的代码,我建议您摆脱灵活数组并在reply字段中维护指向“正常”数组的指针。 Yes, this would mean extra pointer chasing for the CPU but it will be simpler to interoperate with Go.是的,这意味着 CPU 需要额外的指针追逐,但与 Go 互操作会更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM