How to read a string from a C function into Go?

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

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)

huangapple
  • 本文由 发表于 2016年10月24日 15:32:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/40212918.html
匿名

发表评论

匿名网友

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

确定