You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#结构体封送时字节偏移异常问题求助

问题根源:字节序不匹配,而非结构体填充

你遇到的问题根本不是结构体打包/填充的问题——你设置的[StructLayout(LayoutKind.Sequential, Pack = 1)]已经完全禁用了结构体填充,用Marshal.SizeOf(typeof(mystruct))可以验证,结构体总大小是12字节,和你的字节数组长度完全一致,说明没有额外填充。

真正的问题是字节序(端序)不匹配:

  • 你的字节数组中,对应f的字节是0x00, 0x90,这是大端序的存储方式(高位字节在前)
  • 而.NET封送默认使用主机字节序(大部分现代系统是小端序,低位字节在前),所以这两个字节会被解析为0x9000(低字节0x90在前,高字节0x00在后),和你的预期相反。
解决方案

方案1:封送后手动反转字节序

在得到封送后的结构体对象后,对多字节数值类型(uint、ushort)进行字节反转,适配大端序:

// 封送代码不变
GCHandle gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
mystruct output = (mystruct)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(mystruct));
gcHandle.Free();

// 反转字节序适配大端
output.e = ReverseUInt32(output.e);
output.f = ReverseUInt16(output.f);

// 辅助反转方法
private static uint ReverseUInt32(uint value)
{
    return ((value & 0x000000FFU) << 24) |
           ((value & 0x0000FF00U) << 8) |
           ((value & 0x00FF0000U) >> 8) |
           ((value & 0xFF000000U) >> 24);
}

private static ushort ReverseUInt16(ushort value)
{
    return (ushort)(((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8));
}

方案2:手动解析字节数组(更可靠)

跳过封送,直接按字节偏移读取并手动处理字节序,这种方式完全可控,适合固定格式的二进制数据:

byte[] bytes = { 0x07, 0x01, 0x01, 0x01, 0x00, 0xb6, 0xa6, 0xb8, 0x00, 0x90, 0x00, 0x00 };
mystruct output = new mystruct();

output.a = bytes[0];
output.b = bytes[1];
output.c = bytes[2];
output.d = bytes[3];
// 大端解析uint:从字节4到7,高位在前
output.e = (uint)(bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7]);
// 大端解析ushort:字节8是高位,字节9是低位
output.f = (ushort)(bytes[8] << 8 | bytes[9]);
output.g = bytes[10];
output.h = bytes[11];
关于无填充结构体的验证

你当前的结构体定义已经实现了无额外填充,Pack = 1会强制所有字段按1字节对齐,不会在字段之间或末尾添加填充字节。可以用以下代码验证:

int size = Marshal.SizeOf(typeof(mystruct));
Console.WriteLine(size); // 输出12,和字节数组长度一致

内容的提问来源于stack exchange,提问作者Jake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:03:11