如何让 void** 成为 C 库的参数?

How to get a void** to be a parameter of a C library?

我正在尝试使用 cgo 从 GO 调用 C 库。

C库函数如下:

int receive(void** data);

// I'd call it like that:
void* myptr; // myptr=null
int nbBytes = receive(&myptr);
if (nbBytes==0) { return }
// myptr has now an address to a valid buffer that contains nbBytes bytes.

// And then casting it with char* to access the data that can be anything. Example:
printf("%d", *(char*)myptr);

如何从 GO 调用此 receive() 函数? Go 不分配任何内存,内存地址通过 myptr 返回并直接从中访问。

理想情况下,我会通过 []byte 读取数据。

[编辑:您添加了一个说明,说明这不仅仅是建议。但是我们仍然不知道这些数据之后是如何使用的,来自C代码。]

您的问题中没有足够的信息来完整回答它,因为我们不知道——C 语言本身并不能告诉我们——这个 void ** 是如何使用的。您的评论和附加代码 建议 (非常强烈)它的使用方式是 receive 填充指针:

int receive(void **data) {
    *data = <something>;
    return <some value>;
}

我们不知道尖括号中的部分;要使用 C 代码中的这些数据,我们将按照您所说的进行操作:

void f(void) {
    void *p;
    int ret;
    ...
    ret = receive(&p);
}

鉴于这么多和(合理的)假设,我们不知道的是:

  • ret 值表示什么?
  • p之后是否总是有效?
  • *p 有多少字节可访问?

例如,会:

struct our_data dst;
memcpy(&dst, p, len);

是将字节从 p 获取到数据结构 dst 的有效方法,如果是这样,长度 len 从何而来?是否暗示,例如,我们是否知道因为 ret 不是 -1(错误),所以 p 是有效的并且有 sizeof(struct our_data) 字节可用,我们只需要 memcpy使其正确对齐?

如果我们知道所有这些事情,我们就可以直接从 Go 中完成这项工作:

var p unsafe.Pointer
var obj C.struct_our_data
ret := C.receive(&p)
C.memcpy(unsafe.Pointer(&obj), p, len) // or similar with copy()

尽管根据任务等,为原始数据编写反序列化器可能更有意义,我们将原始数据作为 C 内存中的数组获得;参见,例如 How to convert [1024]C.char to [1024]byte.