英文:
How to read a string from a C function into Go?
问题
我正在尝试使用cgo从Go调用一个C函数来读取错误消息。该函数生成的消息长度未知,但小于256个字节。
C语言中的工作示例:
char message[ERROR_SIZE]; //256
last_error( message, sizeof(message) );
printf( "message: %s\n", message );
我在Go中的尝试(不起作用):
var ptr *C.char
C.last_error(ptr, ERROR_SIZE)
var message = C.GoString(ptr)
fmt.Printf("message: %s\n", message)
运行Go代码时,消息为空。Go版本是否需要预先分配消息的空间?如何做到这一点?
根据LPs的评论,更新后的代码可以传递一个数组。这个方法可以工作,但似乎有点笨拙:
var buf [ERROR_SIZE]byte
var ptr = (*C.char)(unsafe.Pointer(&buf[0]))
C.last_error(ptr, len(buf))
var message = C.GoString(ptr)
fmt.Printf("message: %s\n", message)
有没有更简单的方法?
英文:
I'm trying to call a C function from Go with cgo to read an error message. The function produces a message of an unknown length less than 256 bytes.
Working example in C:
char message[ERROR_SIZE]; //256
last_error( message, sizeof(message) );
printf( "message: %s\n", message );
My attempt in Go (not working):
var ptr *C.char
C.last_error(ptr, ERROR_SIZE)
var message = C.GoString(ptr)
fmt.Printf("message: %s\n", message)
When the go code is run, the message is empty. Does the go version need to preallocate space for the message? How to do this?
Update after comment by LPs to pass an array. This works, but seems a bit awkward:
var buf [ERROR_SIZE]byte
var ptr = (*C.char)(unsafe.Pointer(&buf[0]))
C.last_error(ptr, len(buf))
var message = C.GoString(ptr)
fmt.Printf("message: %s\n", message)
Is there a simpler way?
答案1
得分: 3
在你的第一个示例中,你传递了一个nil
指针,所以没有为C.last_error
分配内存来写入输出(幸运的是,它似乎什么都没做)。
你需要以某种方式分配内存,而在Go中最直接的方法是使用切片,而不是创建一个静态大小的数组。
buf := make([]byte, ERROR_SIZE)
C.last_error((*C.char)(unsafe.Pointer(&buf[0])), len(buf))
// 虽然C.GoString会找到终止的空字符,但在C中没有理由复制字符串并分配另一个切片。
if i := bytes.IndexByte(buf, 0); i >= 0 {
buf = buf[:i]
}
fmt.Printf("message: %s\n", buf)
英文:
In your first example you are passing a nil
pointer, so there is no allocated memory for C.last_error
to write the output to (and luckily, it appears to just do nothing).
You need to allocate the memory somehow, and the most straightforward way to do that in Go is to use a slice, rather than create an array with a static size.
buf := make([]byte, ERROR_SIZE)
C.last_error((*C.char)(unsafe.Pointer(&buf[0])), len(buf))
// While C.GoString will find the terminating null if it's there,
// there's no reason to copy the string in C, and allocate another slice.
if i := bytes.IndexByte(buf, 0); i >= 0 {
buf = buf[:i]
}
fmt.Printf("message: %s\n", buf)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论