C#接收C端网络传输char*经Marshal转string乱码问题排查
C#对接C服务端时char*转字符串乱码/访问异常问题
问题场景
开发对接C语言编写服务端的C#客户端应用时,其余基础数据类型传输解析均正常,仅C端char*类型字段转换为C#字符串时出现异常。
原有收发实现逻辑
C端(服务端)实现
采用结构体封装待传输数据,原始结构体定义:
struct NetworkRequest { int value; char *testCharPointer; };
发送时直接将结构体强制转换为char*类型缓冲区通过网络发送,转换代码:
char *buffer = (char *) (void *)request;
C#端(客户端)实现
收到字节数组后,通过Marshal类将字节数组反序列化为对应结构体,转换代码:
static NetworkRequest convertToRequest(byte[] arr) { NetworkRequest str = new NetworkRequest(); int size = Marshal.SizeOf(str); IntPtr ptr = IntPtr.Zero; try { ptr = Marshal.AllocHGlobal(size); Marshal.Copy(arr, 0, ptr, size); str = (NetworkRequest)Marshal.PtrToStructure(ptr, str.GetType()); } finally { Marshal.FreeHGlobal(ptr); } return str; }
异常现象
- 除
char*/string映射字段外,其余基础类型字段解析完全正常 - C端发送内容为
hello的char*字段时,C#端控制台打印得到乱码QÈüìt - 曾尝试给C#结构体字符串字段加
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]标记,对应C#结构体定义如下:
struct NetworkRequest { public int value; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] public string testString; };
如果移除该MarshalAs特性,会直接触发System.AccessViolationException异常。
问题根因
发送结构体时传输的是char*指针本身存储的进程内内存地址,而非指针指向的实际字符串内容。
跨网络传输时,C端进程的独立内存地址对C#端进程完全无效,收到的地址值指向C#进程自身内存空间的随机位置,自然会读取出乱码;直接按无效指针访问内存就会触发访问违例异常。之前尝试用ByValTStr标记的方案本质是按值解析定长字符串内存,和当前传过来的指针值内存布局完全不匹配,也无法正确解析。
修复方案
将C端结构体中的char*指针替换为定长char数组,让字符串内容直接内联存储在结构体内存空间中,发送时随结构体整体被拷贝到缓冲区即可正常传输。
修改后的C端结构体示例:
#define MAX_STR_LEN 100 struct NetworkRequest { int value; char testCharArr[MAX_STR_LEN]; };
注意C端定长数组的长度需要和C#端SizeConst配置的值保持一致,避免结构体内存布局错位导致解析异常,对应C#端保持原有ByValTStr的Marshal标记即可正常解析字符串内容。
内容的提问来源于stack exchange,提问作者ARandomPerson
相关产品推荐
相关产品推荐

