
在 go 中使用 cgo 调用 c 函数时,可直接传入 `nil` 表示 null 指针,但必须确保目标 c 函数明确支持 null 参数;否则将触发段错误。本文详解正确传递方式、安全检查实践及典型示例。
CGO 允许 Go 代码无缝调用 C 函数,其中传递 NULL 指针是一个常见且合法的操作——只需向 C 函数参数传入 Go 的 nil 值即可。例如,C.strcmp(pca, nil) 或 C.strcmp(nil, pcb) 在语法上完全有效,CGO 会自动将其转换为 C 的 NULL(即 (void *)0)。但关键前提在于:该 C 函数必须定义或约定能安全处理 NULL 参数。
以 strcmp 为例:根据 POSIX 和 C 标准,strcmp(const char *, const char *) 的行为在任一参数为 NULL 时是未定义的(undefined behavior)。实际运行中(如 glibc 实现),多数会立即崩溃(如你遇到的 0xc0000005 访问违规异常),因为函数内部直接解引用了空指针。因此,不能仅因语法允许就盲目传 nil 给 strcmp。
✅ 正确做法是:在调用前主动校验输入,避免非法 NULL 传入不兼容函数:
func StrCmp(a, b string) int {
// 空字符串是合法的,但 nil 字符串不可转为 C 字符串
if a == "" && b == "" {
return 0
}
// 若需支持“缺失字符串”语义,应由上层逻辑决定如何映射(如返回 -1 或 panic)
pca := C.CString(a)
defer C.free(unsafe.Pointer(pca))
pcb := C.CString(b)
defer C.free(unsafe.Pointer(pcb))
return int(C.strcmp(pca, pcb))
}⚠️ 注意:C.CString("") 返回的是指向空终止字节 "\x00" 的有效指针,不是 nil,因此上述写法已规避 NULL 风险。
? 对于真正设计为接受 NULL 的 C 函数(如自定义或部分系统 API),传 nil 是安全且推荐的。例如:
/* #includeint handle_optional_ptr(int* p) { if (p == NULL) return -1; // 显式处理 NULL return *p * 2; } */ import "C" // 安全调用:传 nil → C 中 p == NULL result := C.handle_optional_ptr(nil) // 传有效指针 var x C.int = 42 result := C.handle_optional_ptr(&x)
? 关键要点总结:
- nil 在 CGO 中自动映射为 C 的 NULL,语法合法;
- 是否语义合法,取决于 C 函数自身契约——务必查阅文档或源码确认;
- 对 strcmp、strlen、strcpy 等标准字符串函数,严禁传 nil,应提前校验并转换为空字符串或返回错误;
- 若需表达“无值”语义,优先在 Go 层做逻辑判断,而非依赖 C 函数容错;
- 使用 unsafe.Pointer 转换时注意类型匹配(如 (*C.int)(unsafe.Pointer(&goInt))),避免内存越界。
通过严谨的输入验证与对 C ABI 的准确理解,你可以在 CGO 中既安全又高效地利用 NULL 指针这一底层能力。










