structlayout应选sequential或explicit:sequential按声明顺序布局并受pack影响,explicit需fieldoffset实现字段重叠;auto仅限不对外暴露内存的内部场景。

StructLayout 的三种常见值怎么选
结构体默认是 LayoutKind.Auto,但运行时会自动重排字段顺序以优化内存对齐——这会导致无法与 C/C++ 互操作或序列化失败。实际开发中几乎总要显式指定:LayoutKind.Sequential(按声明顺序布局,兼容性最好)或 LayoutKind.Explicit(手动控制每个字段偏移,用于位域、union 等场景)。除非你明确需要 .NET 自动优化且不对外暴露内存,否则别用 Auto。
Sequential 布局下字段顺序和对齐怎么生效
LayoutKind.Sequential 保证字段按代码中声明顺序排列,但对齐仍受 Pack 和字段类型影响。比如 int 默认按 4 字节对齐,若前面是 byte,编译器会在中间插入 3 字节填充。可通过 [StructLayout(LayoutKind.Sequential, Pack = 1)] 强制按 1 字节对齐,避免填充——这对网络协议解析或硬件寄存器映射很关键。但要注意:Pack=1 可能降低访问性能,尤其在 ARM 或某些 CPU 上。
Explicit 布局必须配 FieldOffset 才能编译
用 LayoutKind.Explicit 时,每个字段都必须加 [FieldOffset(n)],否则编译报错 CS0629。它允许字段重叠(模拟 C union),例如同一块内存既当 int 又当两个 short:
[StructLayout(LayoutKind.Explicit)]
public struct IntAsTwoShorts
{
[FieldOffset(0)] public int Value;
[FieldOffset(0)] public short Low;
[FieldOffset(2)] public short High;
}
注意:FieldOffset 值必须是非负整数,且不能超出结构体总大小;重叠字段的读写行为依赖 CPU 端序,跨平台需谨慎。
字符串、数组、引用类型在 StructLayout 中的陷阱
结构体里直接放 string 或托管数组(如 int[])会导致 LayoutKind.Sequential 失效,因为它们是引用类型,内存不在结构体内。正确做法是用 fixed 数组或 MarshalAs:
- 固定长度字符数组:用
fixed char Name[32](需开启unsafe) - 字符串指针:用
IntPtr+Marshal.PtrToStringAnsi - 非托管字符串:加
[MarshalAs(UnmanagedType.LPStr)] public string Name;,但只适用于 P/Invoke 场景
忘了这些限制,结构体传给 C DLL 时大概率崩溃或读到乱码。










