【问题标题】:Windows 64-bit struct size varies with contained data type?Windows 64 位结构大小随包含的数据类型而变化?
【发布时间】:2012-06-05 07:57:25
【问题描述】:

我有两个不同的数据结构,原则上它们应该具有相同的大小,我想知道为什么它们不一样。

struct pix1 { 
    unsigned char r; 
    unsigned char g;
    unsigned char b; 
    unsigned char a; 
    unsigned char y[2]; 
 }; 

struct pix2 { 
    unsigned char r; 
    unsigned char g;
    unsigned char b; 
    unsigned char a; 
    unsigned short y; 
 }; 

然后,我将其中四个像素组合在一起,如下所示:

struct pix4 {
    pix1 pixels[4]; // or pix2 pixels[4]
    unsigned char mask;
};

...但事实证明,这种分组的大小会根据 sizeof(pix4) 发生变化,具体取决于我使用的是 pix1 还是 pix2。单独的 sizeof(pix1) == sizeof(pix2),所以我对为什么将四重像素分组会改变大小感到困惑。我很在意,因为用 short 编写程序比使用 2 个无符号字符更容易,但它每像素要花费我 0.25 个字节。

我不确定这个架构是否特定,因为我没有在其他类型的机器上测试过。可以对齐吗?这是我需要担心的事情,还是我可以继续进行简短的实施?

提前感谢您的帮助。

【问题讨论】:

  • #pragma pack(1) 来获得字节对齐的打包(Visual Studio),那么在这两种情况下你应该得到相同的大小。
  • 正确的封装意味着你不关心确切的表示,只关心提供的接口。即使内部表示使用两个单独的字节,也很容易为y 获取并返回uint16_t 的getter 和setter。
  • @Matthieu M.:你完全正确。 getter 和 setter 应该抽象出单个字节访问,但由于我不精通处理相反字节序的差异,我很担心如果我不正确地处理字节序,我会在代码中引入错误,仅此而已。
  • @Cindeselia:如果你这样做了,那么修复将本地化为 getter 和 setter 代码,这只是两个函数 :)

标签: c++ struct sizeof short


【解决方案1】:

结构的大小相同,但对齐要求不同。

结构的对齐是其所有成员的最大对齐。所以pix1 有对齐1,因为它只有字符,但pix2 有来自短成员的对齐2。 pix4 的对齐然后从 pixels 成员中获取对齐,所以它在第一种情况下为 1,在第二种情况下为 2。

现在,为了确保数组的所有成员都正确对齐,结构的大小会向上舍入到其对齐的下一个倍数。在这两种情况下,pixels 的大小都是 24,但是有 1 个字节的mask。在第一种情况下,对齐是 1,所以 25 是它的倍数,sizeof(pix4) 是 25,但在第二种情况下,对齐是 2,所以 sizeof(pix4) 必须四舍五入到下一个偶数 26。

这在所有平台上都是一样的。

【讨论】:

    【解决方案2】:

    是的,它与对齐有关。编译器想要对齐natural boundaries 上的变量,因此short 将是16 位(2 字节)对齐的。因此包含 short 的结构也将在 16 位边界上对齐。

    【讨论】:

    • @LuchianGrigore:错误,位,而不是字节。自然边界 == 类型的大小。
    • 我从未听说过这个词。介意提供参考吗?
    • @LuchianGrigore:对于 x86,请参见例如intel.com/Assets/PDF/manual/253665.pdf
    • 好吧,对齐要求总是特定于平台的,当 OP 询问 Windows 64 位时,我假设他对 x86-64 感兴趣(Windows IA-64 的用户并不多!)。此外,恕我直言,字对齐并没有描述问题的全部范围,因为不同的类型有不同的对齐要求 - 在您提到的维基百科文章中,自然边界 == 对齐,“非自然”边界 == 未对齐。此外,如果您在谷歌上搜索“对齐自然边界”,您会发现它也用于其他地方,例如在 AIX/POWER 上的 XLC 编译器的文档中。
    【解决方案3】:

    在 Linux 32 位上也有同样的效果。

    出于对齐原因,它与填充有关。

    如果您使用struct pix1,您只有字符,因此struct pix4 可以保持原样。但是如果你使用struct pix2,它会包含一个short。因此,整个结构必须对齐,即使在struct pix4 的数组中,每个元素也必须对齐以干净访问y。

    更详细:具有 2 个元素的 strict pix4 数组的形状如下:

                    +-----     [0]     -----+++-----    [1]     -----+
    First version:  rgbayyrgbayyrgbayyrgbayyMrgbayyrgbayyrgbayyrgbayyM
    Second version: rgbayyrgbayyrgbayyrgbayyM rgbayyrgbayyrgbayyrgbayyM
                    ---------25--------------+ <- +1
    

    为什么?因为---ed 部分是 25 个字节,是奇数。这对于第一个版本没有问题——第二个元素可以愉快地从一个奇数地址开始——但是对于第二个版本。 yy 必须始终位于偶数(对齐)地址上,因此 struct pix4 被设为 26 个字节。

    【讨论】:

    • “必须始终位于偶数(对齐)地址”甚至意味着对齐吗?
    • aligned 有点多:even 只能被 2 整除 - 这对 short 来说已经足够了 - 但在一般情况下(例如 int64_t 和其他东西) - even 还不够。 IOW,“对齐”一词更笼统。
    猜你喜欢
    • 2016-11-21
    • 1970-01-01
    • 2013-04-05
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-27
    相关资源
    最近更新 更多