C#中使用StructLayout从内存取字符串仅返回单个字符问题排查
问题分析与解决方案
看起来你遇到的问题是通过StructLayout读取内存字符串时只拿到了第一个字符"T",而预期是"TEZ",这大概率和内存中字符串的编码格式、终止符,或者FieldOffset的准确性有关,我们来一步步解决:
可能的原因
- 编码不匹配:C#的
string默认基于UTF-16(宽字符),如果内存中的"TEZ"是以UTF-16存储的,那每个字符占2字节——第一个字符'T'是0x54 0x00,此时用sbyte*读取会把0x00当成ASCII的终止符,自然只读到第一个字符。 - 缺少终止符:如果内存中的字符串是ASCII/UTF-8格式,但没有以
\0(null字节)结尾,new string(sbyte*)可能会提前终止,或者读取到乱码,但这里只读到第一个字符,更可能是编码问题。 - FieldOffset错误:0x14这个偏移量可能并没有准确指向字符串的起始位置,导致你读的是其他内存区域的内容。
针对性解决方案
方案1:如果内存中是UTF-16(宽字符)格式
把结构体里的sbyte数组改成char数组(因为char在C#中就是UTF-16的16位字符):
[StructLayout(LayoutKind.Explicit)] public unsafe struct InfoDetails { [FieldOffset(0x14)] public fixed char Name[50]; // 替换为char数组 public string getName { get { fixed (char* namePtr = Name) { return new string(namePtr); // 直接读取UTF-16字符串 } } } }
方案2:如果内存中是ASCII/UTF-8格式且无终止符
如果确定是单字节编码,但内存里没有\0终止符,就手动指定读取长度(比如你预期的3个字符):
[StructLayout(LayoutKind.Explicit)] public unsafe struct InfoDetails { [FieldOffset(0x14)] public fixed sbyte Name[50]; public string getName { get { fixed (sbyte* namePtr = Name) { // 读取前3个字节并转换为字符串 return Encoding.ASCII.GetString(new ReadOnlySpan<sbyte>(namePtr, 3)); // 如果是UTF-8就用Encoding.UTF8.GetString } } } }
额外检查点
- 确认
FieldOffset(0x14)的准确性:可以用调试工具查看内存地址,验证0x14偏移位置是否真的是"T"的起始字节(ASCII的'T'是0x54)。 - 检查内存中的字符串结构:有些内存布局会先存储字符串长度,再存内容,这种情况需要先读取长度值,再根据长度读取对应字节数的内容。
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

