C# 结构体布局StructLayout方法 C#如何控制结构体的内存布局

来源:这里教程网 时间:2026-02-21 17:41:58 作者:

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 时大概率崩溃或读到乱码。

相关推荐