关于结构体的对齐

  这一类型的题目经常在笔试、面试中问到,而很多人虽然答对了,但却了解的不够彻底,所以在此总结下。有错请帮忙指出。

  对齐的原因不多讲了,相信大家都知道。这里只谈它的机制。

 

  在c里,每种数据类型都有自己的对齐方式,包括基本数据类型以及其他的复杂数据类型。对于标准数据类型,它的地址只要是它的长度的整数倍就行了,而非基本数据类型按下面的原则对齐:
    数组:按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。 
    联合:按其包含的长度最大的数据类型对齐。 
    结构体:结构体中每个数据类型都要对齐,结构体本身也要对齐。

  这里主要讨论结构体的对齐方式。(vs 2012下,编译器默认对齐是8字节)

  考虑这样一个结构体:

  

struct A
{
  float f;
  char c;
  short s;
  int i;
}

 

  它的大小是多少呢?答案是12。要搞清楚这一点,需要了解几个概念:

    1. 数据类型的自身对齐大小。比如float,它是4字节的,它自身的对齐大小也是4字节。

    2. 编译器指定的对齐大小。 可以通过#pragma pack (N)来指定,vs下默认是8。

    3. 有效对齐大小。前两者的最小值。有效对齐大小是最终采用的对齐大小,如果其值为N,则该数据的首地址能被N整除。

    4. 结构体本身的有效对齐大小是其数据成员有效对齐大小的最大值。

  在上题中,float自身对齐大小是4字节,而默认对齐大小是8,所以有效对齐大小是4。float是结构体中最大的数据类型,所以结构体自身的有效对齐大小是4,结构体的首地址能被4整除,比如说0x0004.float的首地址与之相同,所以是自然对齐的。数据c自身对齐大小是1,小于指定大小,所以其有效对齐大小是1,由于结构体是顺序连续摆放的,所以其地址是0x0008。s的有效对齐大小是2,其地址要能被2整除,所以他应该放在0x0010,而数据i有效对齐大小是4,应该在0x000C。所以总共是12。

  如果其中有数组怎么办呢?

struct A
{
  float f;
  char c;
  int i;
  char a[10];
};

  上面说过了,数组按照第一个元素对齐。所以这个结构体的大小是4+1+3+4+10=22,还要加上2,结构体的大小要能被其有效对齐大小整除,这里也就是f或者i的有效对齐大小4,所以最终结果是24。

  

#pragma pack (16)

struct A
{
    float f;
    char c;
    int i;
    double a[10];
}; 

  这个结构体的大小呢?答案是96。你明白了吗?

posted @ 2014-03-29 23:46  码的一手好代码  阅读(772)  评论(1编辑  收藏  举报