如何正确将C++ DLL中的const char*转换为C#字符串?
C++ const char* 转 C# 字符串时字符乱码的问题分析与解决
问题根源
你的问题核心是编码不匹配和控制字符的错误解析:
- C++中的
const char*本质是单字节序列,而你传递的字符串包含ASCII控制字符(如\x2、\x3)。使用UnmanagedType.LPStr封送时,CLR会采用当前系统的ANSI代码页(比如Windows-1252)解码字节,而非纯ASCII标准。部分控制字符在ANSI代码页中会被错误映射为可打印字符(例如你遇到的\x2被解析为È)。 - 尝试
LPWStr完全错误,因为它对应C++的宽字符wchar_t*,和你传递的单字节const char*类型不兼容,必然导致乱码。
解决办法
1. 封送为IntPtr,手动按指定编码转换(最可靠)
避免直接封送为string,先把const char*转为IntPtr,再手动读取字节数组并按目标编码转换,确保控制字符和特殊字符都被正确解析:
修改C#委托定义:
private delegate void OnPlayerTextMessageReceivedCallback( IntPtr senderEntityIdPtr, IntPtr messagePtr );
回调方法中处理字符串:
private void OnPlayerTextMessageReceived(IntPtr senderPtr, IntPtr messagePtr) { // 方式1:直接用ANSI读取(依赖系统代码页,适合包含扩展ASCII字符如ß的场景) string sender = Marshal.PtrToStringAnsi(senderPtr); string message = Marshal.PtrToStringAnsi(messagePtr); // 方式2:手动读取字节数组,按明确编码转换(更严谨,适合控制字符多的场景) // List<byte> messageBytes = new List<byte>(); // int offset = 0; // byte currentByte = Marshal.ReadByte(messagePtr, offset); // while (currentByte != 0) // { // messageBytes.Add(currentByte); // offset++; // currentByte = Marshal.ReadByte(messagePtr, offset); // } // // 如果是纯ASCII用Encoding.ASCII,包含扩展字符用对应编码如Windows-1252 // string message = Encoding.GetEncoding(1252).GetString(messageBytes.ToArray()); }
2. 明确指定解码编码
如果必须用string作为委托参数,需确保解码编码和C++端一致:
- 若C++字符串是纯ASCII,在C#中封送后用
Encoding.ASCII重新处理(但LPStr可能已经用系统代码页解析,所以还是手动转字节数组更可靠)。 - 若包含扩展ASCII字符(如
ß),用对应编码(比如Windows-1252)解码:byte[] messageBytes = Encoding.Default.GetBytes(message); string correctMessage = Encoding.GetEncoding(1252).GetString(messageBytes);
关键注意事项
- 禁止混用单字节和宽字符封送:
LPWStr和const char*类型不匹配,绝对不能使用。 - 控制字符(如
\x2、\x3)依赖固定编码解析,避免依赖系统默认ANSI代码页,否则不同系统会出现不同乱码。
内容的提问来源于stack exchange,提问作者JonRicardo
相关产品推荐
相关产品推荐

