C++ Windows 64位结构大小因包含的数据类型而异?

C++ Windows 64位结构大小因包含的数据类型而异?,c++,struct,sizeof,short,C++,Struct,Sizeof,Short,我有两个不同的数据结构,原则上应该具有相同的大小,我想知道为什么它们没有 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;

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

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字节

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


提前感谢您的帮助。

同样的效果也适用于32位Linux

由于对齐的原因,它与填充有关

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

更详细:包含2个元素的
严格pix4
数组的形状如下:

                +-----     [0]     -----+++-----    [1]     -----+
First version:  rgbayyrgbayyrgbayyrgbayyMrgbayyrgbayyrgbayyrgbayyM
Second version: rgbayyrgbayyrgbayyrgbayyM rgbayyrgbayyrgbayyrgbayyM
                ---------25--------------+ <- +1
+-[0]-+++-[1]-----+
第一版:rgbayRgbayRgbayRgbayMRgbayRgbayRgbayRgbayRgbayRgbayYMM
第二个版本:rgbayRgbayRgbayRgbayRgbayRgbayRgbayRgbayRgbayRgbayRgbayM

---------25------------+是的,它与对齐有关。编译器希望对齐上的变量,因此短字符将对齐16位(2字节)。因此,包含short的结构也将在16位边界上对齐。

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

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

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


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

#pragma pack(1)要获得字节对齐的打包(visual studio),那么在这两种情况下,您应该获得相同的大小。正确的封装意味着您不关心确切的表示,只关心所提供的接口。为
y
设置一个getter和setter是很容易的,它获取并返回
uint16\u t
,即使内部表示使用了两个单独的字节。@Matthieu M:你完全正确。getter和setter应该抽象出单独的字节访问,但是由于我不太熟悉处理相反的endian的差异,我担心如果我错误地处理endianness,我会在代码中引入bug,仅此而已。@Cindeselia:如果你这样做,那么修复将局限于getter和setter代码,只有两个函数:)@LuchianGrigore:Err,bit,而不是byte。自然边界==类型的大小。我从未听说过这个术语。介意提供一个参考吗?@LuchianGrigore:对于x86,请参见,例如,校准要求始终是特定于平台的,当OP询问Windows 64位时,我认为他对x86-64感兴趣(不是很多Windows IA-64用户!)。此外,单词aligned并没有描述问题的全部范围,因为不同类型的词有不同的对齐要求——正如您提到的维基百科文章所述,自然边界==对齐,“非自然”边界==未对齐。此外,如果你在谷歌上搜索“对齐自然边界”,你会发现它也在其他地方使用,例如在AIX/POWER上的XLC编译器文档中。“必须始终位于偶数(对齐)地址上”是否表示对齐?对齐的意思稍微多一些:偶数可以被2整除-这对于
short
,已经足够了-但在一般情况下(例如of
int64\t
之类的)-即使是也不够。照此,术语“aligned”更一般。