如何在CGO中从C Union读取char*字符串?
从C联合体的value_struct中读取char*字符串到Go的正确方法
我有一个用于存储数据的C联合体,定义如下:
union data_union { char *string_val; int8_t int8_val; int64_t int64_val; // 其他类型 }; typedef enum { MY_STRING, MY_INT8, MY_INT64, // 其他类型 } data_type; struct value_struct { data_type type; data_union data; };
目前我可以通过以下方式从C的value_struct中读取int8值到Go:
int8_val := *(*C.int8_t)(unsafe.Pointer(&(cValue.data[0]))) goInt := int64(int8_val)
读取int64值的方式类似:
int64_val := *(*C.int64_t)(unsafe.Pointer(&(cValue.data[0]))) goInt := int64(int64_val)
但读取char*类型的空终止字符串时,尝试了三种方法都得到垃圾值或无效结果,寻求正确的读取方式:
尝试过的三种方法
方法一
string_val := C.GoString((*C.char)(unsafe.Pointer(&(cValue.data[0]))))
方法二
var cString []byte ptr := unsafe.Pointer(&(cValue.data[0])) for { char := *(*C.char)(ptr) if char == 0 { break } cString = append(cString, byte(char)) ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(char)) } goString := string(cString)
方法三
cStringPtr := (*byte)(unsafe.Pointer(&(cValue.data[0]))) cString := unsafe.Slice(cStringPtr, 0) // 转换为Go字符串 goString := string(cString)
正确的读取方法
问题核心是:联合体中的string_val本身是一个指针类型,你需要先读取这个指针的值,再用它访问字符串内容,而非直接把联合体的首地址当作字符串首地址。
方案1:直接访问联合体字段(如果Go绑定支持)
// 读取联合体中存储的char*指针 strPtr := (*C.char)(unsafe.Pointer(&(cValue.data.string_val))) // 转换为Go字符串 goString := C.GoString(strPtr)
方案2:通过指针类型转换读取(适用于无法直接访问字段的场景)
// 获取联合体首地址(存储char*值的内存位置) strPtrAddr := unsafe.Pointer(&(cValue.data[0])) // 解引用得到真正的字符串指针 strPtr := *(*C.char)(strPtrAddr) // 转换为Go字符串 goString := C.GoString(strPtr)
原错误逻辑是把联合体的首地址直接转换成*C.char,但这个地址里存储的是char*的指针值,而非字符串的首字节,所以必须先解引用拿到真正指向字符串的指针,再传递给C.GoString处理。
内容的提问来源于stack exchange,提问作者Abrar Ahmed
相关产品推荐
相关产品推荐

