通过dllexport传递std::string:C#与非托管C++桥接问题
解决C#到C++桥接层字符串转std::string乱码的问题
嘿,这个乱码问题我之前帮人排查过好几次,核心就是C#和C++的字符串编码体系不一样搞的鬼!C#的string默认是UTF-16编码的Unicode字符串,而你直接转std::string时没处理编码转换,自然就出现乱码了。下面给你几个靠谱的解决思路,按实用性排序:
方案1:用UTF-8字节数组传递(最稳妥,跨平台通用)
UTF-8是跨语言跨平台的通用编码,std::string天然可以存储UTF-8的字节流,这种方式几乎不会出问题。
C#端代码
[DllImport("你的桥接层.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void BridgeFunction(byte[] utf8Bytes, int byteCount); // 调用时的转换逻辑 string inputStr = "要传给C++的字符串"; byte[] utf8Bytes = Encoding.UTF8.GetBytes(inputStr); BridgeFunction(utf8Bytes, utf8Bytes.Length);
C++桥接层代码
extern "C" __declspec(dllexport) void BridgeFunction(const char* utf8Data, int dataLength) { // 注意这里要用带长度的构造函数,避免遇到'\0'提前截断(比如字符串里有嵌入的空字符) std::string targetString(utf8Data, dataLength); // 直接调用目标DLL的函数 TargetDllFunction(targetString); }
方案2:用.NET新版本的UTF-8直接映射(代码更简洁)
如果你的项目用的是.NET Core 3.0+或者.NET 5及以上版本,可以直接用MarshalAs指定UTF-8编码,省去手动转字节数组的步骤:
C#端代码
[DllImport("你的桥接层.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void BridgeFunction([MarshalAs(UnmanagedType.LPUTF8Str)] string input); // 调用就很简单了 BridgeFunction("要传递的字符串");
C++桥接层代码
extern "C" __declspec(dllexport) void BridgeFunction(const char* utf8Str) { std::string targetString(utf8Str); TargetDllFunction(targetString); }
方案3:兼容旧.NET框架的ANSI编码(仅限特定场景)
如果你的项目还在使用.NET Framework 4.x这类旧框架,默认的CharSet.Ansi会把C#字符串转成系统默认编码的char*(比如中文Windows是GBK)。这种方式要注意:只有当目标DLL明确支持系统默认ANSI编码时才用,否则还是会乱码。
C#端代码
[DllImport("你的桥接层.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern void BridgeFunction(string input);
C++桥接层代码
extern "C" __declspec(dllexport) void BridgeFunction(const char* ansiStr) { std::string targetString(ansiStr); TargetDllFunction(targetString); }
为啥你之前的转换会乱码?
你之前直接用std::string(foo)转换,大概率是这俩原因:
- 要么C#默认传递的是ANSI编码的
char*(比如GBK),但目标DLL期望的是UTF-8,编码不匹配就乱码; - 要么你误把UTF-16的宽字符当成了
char*来转,每个Unicode字符的低字节被当成ASCII处理,自然就变成乱码了。
内容的提问来源于stack exchange,提问作者FlawTECH
相关产品推荐
相关产品推荐

