英文:
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 intomyptr
. 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 = <something>;
return <some value>;
}
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(&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(&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(&p)
C.memcpy(unsafe.Pointer(&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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论