结构中字段对齐的奇怪行为

时间:2015-01-13 20:18:36

标签: c++ windows visual-studio-2010

#include <iostream>
using namespace std;
#pragma pack(push, 4)
struct Foo
{
    char ch;   //1
    char ch2;  //1
    char ch3;  //1
    char ch4;  //1 _4
    char ch5;  //1
    short num; //2
    char ch6;  //1 _4
    int num2;  //4 _4
};
#pragma pack(pop)

int main() {
    cout << sizeof( Foo );
    return 0;
}

为什么输出是16个字节?我认为它必须是12因为:

4 char = 4 bytes  
char + short + char = 4 bytes  
int = 4 bytes  

那么有人可以解释剩下的4个字节在哪里吗?

3 个答案:

答案 0 :(得分:3)

你得到的是内存中的以下内容(| s是4字节边界):

|char char char char|char 1bytePadding short|char 3bytesPadding|int|

short需要与2字节边界对齐,因此在前面的char之后插入一个填充字节,以便它可以。类似地,int必须是4字节对齐的,所以在char 3个字节的填充必须插入之后才可以。如果您正在优化空间,经验法则是从大到小对成员进行排序。如果您这样做,那将是:

|int|short char char| char char char char|

这将需要12字节,正如您所期望的那样。

答案 1 :(得分:2)

这与对齐

有关

简而言之,如果不同的值在内存中“对齐”,CPU会更喜欢。例如,如果您正在处理标准的32位整数(4个字节),那么大多数CPU都希望它驻留在可由4分割的内存地址中。因此,10004的内存地址可以正常,10008即可,但10005不会正常。

处理未对齐值时,大多数CPU都会抛出异常并拒绝处理。然而,我们可靠的x86是一个例外,它将正确处理它 - 尽管速度要慢得多。在幕后,它将从内存中获取2个对齐的整数,然后旋转这些位以从中提取未对齐的整数。 (在其他平台上,我认为编译器会生成额外的指令来完成这项工作,但我不确定)所以你真的不希望这种情况发生,除非你有充分的理由为了它。

这就是为什么你的编译器在struct成员之间生成一些填充字节的原因 - 这样short将在偶数地址中,而int将在一个地址中可分为4。

#pragma pack会对此产生影响,但前提是您将其设置为小于4。而且你会得到我之前提到的对齐问题。

答案 2 :(得分:1)

这是你的偏移结构:

struct Foo
{
    0:  char ch;   //1
    1:  char ch2;  //1
    2:  char ch3;  //1
    3:  char ch4;  //1 
    4:  char ch5;  //1
    5:  _padding   //1
    6:  short num; //2
    8:  char ch6;  //1 
    9:  _padding   //3
    12: int num2;  //4 
    16:
};

作为你的平台上的short有2个字节对​​齐,在num之前添加了1个字节填充,使其偏移可分为2.然后在ch6之后有3个字节来进行偏移由{4}划分的num2