Golang中Cgo编译的C-shared二进制字符串从C++返回时出现乱码问题
Golang中Cgo编译的C-shared二进制字符串从C++返回时出现乱码问题 我有一段使用cgo编译为C共享库的Go代码。这段代码随后在一个使用gcc在Ubuntu下编译的C++文件中使用。
当我在M1 Mac上编译并使用这段代码时,一切正常,函数在C++中返回的字符串看起来是正常的。然而,当我在Ubuntu上编译时(代码完全相同),函数运行没有错误,但函数返回的字符串却是这种奇怪的乱码编码。它看起来像下面这样,但每次运行的结果都不同。我不认为这是加密,因为在C代码内部的返回字符串是正常的。

func GetOsStore(serviceName *C.char, keyName *C.char) *C.char {
fmt.Println("GetOsStore start")
backendType, err := getBackendType()
if err != nil {
panic("Getting backend type has failed! " + err.Error())
}
fmt.Println("GetOsStore.BackendType", backendType)
ring, openErr := keyring.Open(keyring.Config{
AllowedBackends: []keyring.BackendType{backendType},
ServiceName: C.GoString(serviceName),
})
if openErr != nil {
fmt.Println("GetOsStore open keyring error", openErr)
} else {
fmt.Println("GetOsStore opened keyring")
}
i, getErr := ring.Get((C.GoString(keyName)))
dataStr := string(i.Data[:])
returnStr := (*C.char)(C.CString(dataStr)) // returnStr prints without issue
defer C.free(unsafe.Pointer(returnStr))
if getErr != nil {
fmt.Println("GetOsStore get keyring error", getErr)
} else {
fmt.Println("GetOsStore got keyring")
}
fmt.Println("GetOsStore end")
return returnStr
}
Napi::String getOsStore(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string serviceNameArg = info[0].As<Napi::String>().ToString();
char *serviceName = new char[serviceNameArg.length() + 1];
strcpy(serviceName, serviceNameArg.c_str());
std::string keyNameArg = info[1].As<Napi::String>().ToString();
char *keyName = new char[keyNameArg.length() + 1];
strcpy(keyName, keyNameArg.c_str());
Napi::String result = Napi::String::New(env, GetOsStore(serviceName, keyName));
std::string resultStr = result.ToString();
cout << "getOsStore from c++ string: " << resultStr; // both these cout produce the encoded text
char *resultCStr = new char[resultStr.length() + 1];
strcpy(resultCStr, resultStr.c_str());
cout << "getOsStore from c string: " << resultCStr;
delete [] serviceName;
delete [] keyName;
return result;
}
更多关于Golang中Cgo编译的C-shared二进制字符串从C++返回时出现乱码问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中Cgo编译的C-shared二进制字符串从C++返回时出现乱码问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个典型的跨平台内存管理和字符串编码问题。问题出现在Go返回的C字符串在C++端的处理方式上。
在你的Go代码中,C.CString()创建了一个以null结尾的C字符串,这个字符串在Go的堆上分配。问题在于Ubuntu和macOS可能有不同的内存对齐或字符串处理方式。
以下是修复方案:
// 在Go端,确保正确处理字符串编码
func GetOsStore(serviceName *C.char, keyName *C.char) *C.char {
// ... 你的现有代码 ...
dataStr := string(i.Data[:])
// 关键修复:显式转换为UTF-8并确保null终止
utf8Str := C.CString(dataStr)
// 不要在这里defer,因为C++端需要这个内存
// defer C.free(unsafe.Pointer(utf8Str))
return utf8Str
}
// 添加一个专门的释放函数
//export FreeCString
func FreeCString(str *C.char) {
C.free(unsafe.Pointer(str))
}
在C++端,需要修改为:
extern "C" {
char* GetOsStore(const char* serviceName, const char* keyName);
void FreeCString(char* str);
}
Napi::String getOsStore(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string serviceNameArg = info[0].As<Napi::String>().ToString();
std::string keyNameArg = info[1].As<Napi::String>().ToString();
// 直接传递std::string的c_str()
char* result = GetOsStore(serviceNameArg.c_str(), keyNameArg.c_str());
if (result == nullptr) {
return Napi::String::New(env, "");
}
// 使用正确的编码转换
Napi::String jsResult = Napi::String::New(env, result, strlen(result));
// 释放Go分配的内存
FreeCString(result);
return jsResult;
}
或者使用更安全的字符串处理:
Napi::String getOsStore(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 2) {
Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
if (!info[0].IsString() || !info[1].IsString()) {
Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
std::string serviceName = info[0].As<Napi::String>().Utf8Value();
std::string keyName = info[1].As<Napi::String>().Utf8Value();
char* cResult = GetOsStore(serviceName.c_str(), keyName.c_str());
if (cResult == nullptr) {
return Napi::String::New(env, "");
}
// 显式指定字符串长度
std::string resultStr(cResult);
Napi::String jsResult = Napi::String::New(env, resultStr);
FreeCString(cResult);
return jsResult;
}
还需要在Go端导出函数时确保正确的调用约定:
/*
#include <stdlib.h>
*/
import "C"
//export GetOsStore
func GetOsStore(serviceName *C.char, keyName *C.char) *C.char {
// 函数实现
}
编译时确保使用相同的字符编码:
# 在Ubuntu上编译时指定UTF-8编码
CGO_CFLAGS="-finput-charset=UTF-8 -fexec-charset=UTF-8" go build -buildmode=c-shared -o libstore.so
问题通常源于:
- Go和C++之间的内存管理不一致
- 字符串编码不匹配(UTF-8 vs 其他编码)
- 平台相关的内存对齐差异
- 缺少null终止符或字符串长度计算错误
使用上述修复应该能解决Ubuntu上的乱码问题。

