
本文详解如何通过 CGO 将 Go 字符串正确转换并复制到 C 的 `char ` 类型,强调内存分配与释放的关键规则,避免常见误用(如直接赋值或内存泄漏)。
本文详解如何通过 cgo 将 go 字符串正确转换并复制到 c 的 `char *` 类型,强调内存分配与释放的关键规则,避免常见误用(如直接赋值或内存泄漏)。
在 Go 中调用 C 函数时,常需将 Go 字符串传递给期望 char * 参数的 C 接口。但 Go 字符串与 C 字符串内存模型不同:Go 字符串是不可变的、带长度的字节序列,而 C 字符串是以 \0 结尾的可变内存块。因此不能直接赋值或修改 C.GoString() 返回的 Go 字符串副本——该函数仅用于从 C 内存读取内容,且返回值为只读 Go 字符串,不可反向写入。
正确做法是使用 C.CString() 函数:它会分配一块新的 C 堆内存,将 Go 字符串内容(含终止空字节
正确做法是使用 C.CString() 函数:它会分配一块新的 C 堆内存,将 Go 字符串内容(含终止空字节 \0)复制进去,并返回 *C.char。示例如下:
)复制进去,并返回 *C.char。示例如下:package main
/*
#include <stdlib.h>
*/
import "C"
import (
"unsafe"
)
func copyStringToC() *C.char {
str := "hello, world"
cstr := C.CString(str) // ✅ 正确:分配并复制
return cstr
}
// 使用后必须手动释放,否则导致内存泄漏
func freeCString(cstr *C.char) {
if cstr != nil {
C.free(unsafe.Pointer(cstr))
}
}⚠️ 关键注意事项:
- C.CString() 返回的指针指向 C 堆内存,Go 的垃圾回收器不会管理它;
- 每次调用 C.CString() 都需配对调用 C.free(),通常应在 C 函数调用完成后、且确认 C 侧不再访问该内存时释放;
- 不要对 C.CString() 返回的指针做越界写操作,也不应将其传给多个 C 函数长期共享(除非明确约定所有权);
- 若需频繁转换,可考虑复用缓冲区或使用 C.CBytes() + 手动添加 \0,但 C.CString() 是最简洁安全的默认选择。
总结:C.GoString(cstr) = str 是语法错误且语义错误——C.GoString() 是函数调用,返回值不可赋值;真正可用的是 cstr = C.CString(str),并务必配套 C.free() 实现内存安全。


















