问题描述
我试图在 go 程序的 c 库中使用 c 字符串,但发生错误:
a.h
文件:
extern const char *s[];
a.c
文件:
const char *s[] = {"a","b","c"};
我将这两个文件编译为 liba.a
main.go
文件:
package main
// #cgo LDFLAGS: -L${SRCDIR} -la
// #include"a.h"
import "C"
import "fmt"
func main() {
x := 1
fmt.Println(x)
fmt.Println(len(C.s))
fmt.Println(C.GoString(C.s[x]))
}
然后我用命令运行代码
go run main.go
我收到错误:
panic: runtime error: index out of range [0] with length 0
怎么解决?谢谢
go 版本:go version go1.15.7 linux/amd64
解决方法
cgo 不透明地处理 C 中的数组。
有所谓的惯用 Go 将 C 内存映射到 Go 可以自然操作的东西。这是一个工作示例 (main.go
):
package main
import (
"fmt"
"unsafe"
)
// #cgo LDFLAGS: -L${SRCDIR} -la
// #include "./a.h"
import "C"
func main() {
x := 1
fmt.Println(x)
fmt.Println(len(C.s)) // Note,Go has no idea so it says 0.
cStr := (*[1 << 30]*C.char)(unsafe.Pointer(&C.s))[x]
fmt.Println(C.GoString(cStr))
}
关键部分是 (*[1 << 30]*C.char)(unsafe.Pointer(&C.s))
。这意味着将 &C.s
解释为一个非常大的常量大小数组(“对任何人来说都足够大”...),但仅从中提取感兴趣的元素 [x]
。
unsafe.Pointer()
的使用应该是一个警告,即超出实际 C 数组的末尾将产生不可预测的结果。事实上,它可能会导致程序崩溃。