如何将void**作为C库的参数获取?

huangapple go评论94阅读模式
英文:

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

问题

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

C库有以下函数:

int receive(void** data);

// 我会这样调用它:
void* myptr; // myptr=null
int nbBytes = receive(&myptr);
if (nbBytes==0) { return }
// myptr现在有一个指向包含nbBytes字节的有效缓冲区的地址。

// 然后使用char*进行类型转换,以访问数据,数据可以是任何类型。例如:
printf("%d", *(char*)myptr);

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

  • receive()是一个“无复制”函数,它将实际数据的地址写入myptr。然后可以使用*(char*)myptr访问数据。
  • 我们可以假设receive()分配和释放缓冲区,对于库的用户来说,这是隐藏的。

理想情况下,我希望能够通过[]byte在Go中读取数据。

英文:

I'm trying to call a C library from GO using cgo.

The C library has the following function:

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);

How can I call this receive() function from GO? Go doesn't allocate any memory, the memory address is returned via myptr and directly access from it.

  • receive() is a "no-copy" and writes the actual data's address into myptr. The data is then accessed using *(char*)myptr.
  • we can assume receive() allocates and frees the buffer, it's hidden from the lib's user

Ideally, I would read the data via []byte in go.

答案1

得分: 2

你的问题中没有足够的信息来完全回答,因为仅凭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) // 或者使用copy()函数类似的方法

不过,根据任务等因素,可能更有意义的是编写一个用于原始数据的反序列化器,我们可以将其作为存储在C内存中的数组获取;参考:https://stackoverflow.com/q/27532523/1256452。

英文:

[Edit: you added a clarification that says this isn't just suggested. But we still don't know how the data are used afterward, from C code.]

There is not enough information in your question to answer it completely, because we don't know—the C language alone doesn't tell us—how this void ** is used. Your comments and additional code suggest (pretty strongly) that the way it's used is that receive fills in the pointer:

int receive(void **data) {
    *data = &lt;something&gt;;
    return &lt;some value&gt;;
}

where the angle-bracketed sections are unknown to us; to use this data from C code, we'd do just what you said:

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

What we don't know, given this much and the (justifiable) assumptions, are:

  • What does the ret value indicate?
  • Is p always valid afterward?
  • How many bytes at *p are accessible?

For instance, would:

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

be a valid way to get the bytes from p into the data-structure dst, and if so, where does the length len come from? Is it implied, e.g., do we know that because ret was not -1 (error) that p is valid and has sizeof(struct our_data) bytes available, and we need the memcpy just to make it properly aligned?

If we knew all of these things, we'd be able to do the job directly from Go:

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

although it might—depending on task etc—make more sense to just write a deserializer for the raw data, which we obtain as an array living in C memory; see, e.g., https://stackoverflow.com/q/27532523/1256452.

huangapple
  • 本文由 发表于 2021年12月27日 22:33:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/70496846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定