这一期我们讲一讲 CGO 中关于 C 数组、字符串、指针等类型的转换。
数组、字符串类型
学过 C 语言的都知道,数组名其实对应于一个指针,该指针指向某一类型的一段内存。而在 Go 语言中,数组是一种值类型,数组长度也是数组类型的一个部分。在 CGO 的 C 伪包中,有一组函数可以用于 Go 语言和 C 语言之间数组以及字符串之间的转换:
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
// Go []byte slice to C array
// The C array is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CBytes([]byte) unsafe.Pointer
// C string to Go string
func C.GoString(*C.char) string
// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
C.CString
把 Go 语言字符串复制成为一个 C 语言字符串,其字符串由 C 语言的 malloc
函数分配,不使用时需要通过 C 语言的 free
函数释放。
C.CBytes
把 Go 语言字节切片复制成为一个 C 语言字节数组,其返回的数组需要在合适的时候释放。
C.GoString
把 C 语言字符串复制成为一个 Go 语言字符串。
C.GoStringN
同样是一个字符数组复制函数。
C.GoBytes
把 C 语言数组复制成为一个 Go 语言字节切片。
在 C 语言中可以通过 GoString
和 GoSlice
来访问 Go 语言的字符串和切片。如果是 Go 语言中数组类型,可以将数组转为切片后再行转换。如果字符串或切片对应的底层内存空间由 Go 语言的运行时管理,那么在 C 语言中不能长时间保存 Go 内存对象。
指针类型
在 Go 语言中,指针的使用比在 C 语言中严格,之前我们就提到在 Go 语言中指针是不能做加减操作的,所以在 CGO 中指针的转换就需要解决这些问题。
在 CGO 中,任何类型的指针都能强制转换成 unsafe.Pointer
指针类型去掉原有的类型信息,然后再重新赋予新的指针类型而达到指针间的转换的目的。例如:
var p *X
var q *Y
q = (*Y)(unsafe.Pointer(p)) // *X => *Y
p = (*X)(unsafe.Pointer(q)) // *Y => *X
参考文献:
[1] 柴树杉;曹春晖, Go 语言高级编程, 北京: 人民邮电出版社, 2019.
👇希望对你有帮助,期待你的关注👇