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

C#中含ushort的结构体设置[StructLayout(LayoutKind.Sequential,Pack=4)]为何不生效?

C#结构体Pack=4时大小不符合预期的原因解析

示例代码

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct OOP_DATE_T  //tag_Date
{
    public ushort year;       
    public byte month;       
    public byte mday;      
    public byte wday;       
};


public class Example
{
    public unsafe static void Main()
    {
        OOP_DATE_T ex = new OOP_DATE_T() { 
            year = 2022,
            month = 12,
            mday = 1,
            wday = 1
        };

        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(OOP_DATE_T));

        //Console.WriteLine(Marshal.SizeOf<OOP_DATE_T>());

        Console.WriteLine("year Offset: {0}", (byte*)&ex.year - addr);
        Console.WriteLine("month Offset: {0}", &ex.month - addr);
        Console.WriteLine("mday Offset: {0}", (byte*)&ex.mday - addr);
        Console.WriteLine("wday Offset: {0}", (byte*)&ex.wday - addr);
    }
}

问题现象

运行代码后输出:

Size: 6
year Offset: 0
month Offset: 2
mday Offset: 3
wday Offset: 4

按照4字节对齐规则,预期结构体大小应为8,但实际是6。设置Pack=1和Pack=2时sizeof结果符合预期,而在结构体中添加int变量后,Pack=4也能让sizeof结果按4字节对齐。

原因解析

核心是**sizeof和Marshal.SizeOf的计算规则完全不同**:

  • [StructLayout]的Pack属性是为非托管互操作设计的,它控制的是结构体在非托管内存中的布局和大小,对应的是Marshal.SizeOf的计算结果。如果你把代码中注释的Marshal.SizeOf打开,会得到结果8,这才是符合4字节对齐的非托管大小。
  • 你用的sizeof(OOP_DATE_T)计算的是CLR托管内存中结构体的大小,CLR会按自身逻辑优化布局:
    1. 字段对齐取「字段自身大小」和Pack值的较小值。你的结构体最大字段是ushort(2字节),Pack=4,所以字段按2字节对齐:year占0-1字节,month在2,mday在3,wday在4,总长度5字节。
    2. 结构体整体大小会向上对齐到「最大字段大小」和Pack值的较小值(也就是2字节),所以5向上取整到6,这就是输出Size=6的原因。

为什么其他场景看起来正常?

  • 当Pack=1或Pack=2时,「最大字段大小」和Pack值的关系刚好匹配,sizeof的结果和你预期的对齐规则一致。
  • 添加int变量后,最大字段大小变成4,和Pack=4相等,结构体整体对齐到4字节,sizeof结果自然变成4的倍数,看起来Pack=4生效了。

内容的提问来源于stack exchange,提问作者garen.X

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:50:59