c/c++结构体对齐小结

因为我看C++对象模型的时候,遇到了几个内存布局都是有关于对齐的一些细节,故此对结构体对齐再做一份小结,有人说:结构体对齐这个东西是依赖于编译器的,因此不用去研究,真的嘛?

 

也许是,也许不是,要看你是做那个行业的了,如果你是做系统地层,网络通讯,嵌入式系统的,一个字节的节省,也许对你是很大的期望呢。虽然具体的对齐方式是因编译器而异,但是对齐的基本原理是不变的,那个原理也许能指导我们编写程序的时候按照某个原则去进行。

 

不过,既然你用到了C或者C++,就多数是和系统底层有缘之人了,你说是嘛?呵呵。

 

现在先说在windows x86 32位机子下的MS vs2005编译器(就是:cl.exe for x86)下的对齐规则:

 

比如以下的结构体定义:

 

struct A

{

    int i;

    double d;

    char c;

};

 

sizeofstruct A)在vs2005的大小?

 

现在说一下cl.exe(就是微软vs2005的编译器进程)在默认情况下是怎么做的:

 

1、对齐量的确定:找到A中最大的基本类型成员的大小,在本例中是8(double的大小).

 

2、当定义一个结构体变量struct A aA; 的时候,aA的起始地址要被由1确定的对齐量整除,在这个例子里,aA的起始地址一定要能被8整除)

 

2、然后开始分配int i4字节的空间;再分配double d;注意double 8字节,所以要分配在被8整除的地方,因此int  i后面空了4字节填充;

 

3、然后,分配char c1字节,这个时候struct A的大小是4(这是int i;的) + 4 (这是填充的) + 8(这是double d;的) + 1 (这是char c;的)= 17

 

4、最后,要求结构体总的大小要能被由1确定的对齐量整除,在这里是说struct A的大小要能被8整除,所以还要加上7字节的填充字符,一共是24字节。

 

从这里可以看出,vs2005的编译器的结构体填充有这样的规则(默认情况下,这个默认情况可以通过工程属性上面的选项修改):

 

1、对齐量的确定:结构体中最大的数据成员的字节数

 

2、当定义一个结构体变量的时候,起始地址一定能被确定的对齐量整除;

 

2、分配每一个成员的时候,该成员相对于起始地址的偏移(offset)要能被该成员的大小整除;

 

3、结构体总的大小能被确定的对齐量整除;

 

 

 

扩充的字节叫做pad(填充字节)

 

 

下面看linux g++ 3.4.3编译器在x86 32位机子下的默认规则,那相对简单一些:(相当于VS2005中将对齐情况改成4字节对齐)

 

对齐的方式默认是4字节,所以每个成员都按照4字节方式对齐即可。上面的结构体的大小就是:

 

4 (int i;的大小) + 8double 的大小) + 1char 的大小) + 3 (为了4字节填充而补充的字节) = 16字节;

 

至于gcc的结构体变量的首地址分配的特征一时也找不到,还望各位多多指教。谢谢。

 

最后,如果定义一个没有任何成员的结构体,struct A{}; 该大小是多少呢?是1字节。如果定义了两个结构体变量struct A a1, a2; 1字节的填充能够使a1a2的地址区分开来!

 

还有其他的编译器和操作系统就不是我所能知的了。

 

那么,这些规则也许不尽相同,但是给了我们一个编程时候的注意点,就是:

 

定义结构体的时候,成员最好能从大到小来定义,那样能相对的省空间。(至少不会比别的顺序差,一般情况下哈。)

 

比如以上的结构体,如果能这样定义:

 

struct A

{

    double d;

    int i;

    char c;

};

 

那么,无论是windows下的vs2005,还是linux下的gcc,都是16字节。

 

对齐情况还可以通过各个编译器给出的特性在代码中改,不过我没用过,就没有发言权,各位又需要可以参考别的文章。

 

以上的过程和推论是我看别的文章和上机试验的结果,如有不对之处,请各位指教,谢谢。

 

 

再说一点,对于有嵌套的情况,vs2005下的对齐我也不大确定,不过我的分析如下:

 

struct A

{

    char c;

    double d;

    int i;

};

 

struct B

{

    struct  A a;

    char c;

};

 

这种情况下,分析B的大小;

 

1、对齐量的确定:包括A中的各成员比较的,递归下去,比较各个基本类型成员的大小,去最大值,为8(double的大小);

 

2、起始地址和上面的一样,要求B的变量的其实地址能被8整除;

 

3、关于B中struct A a;的偏移和大小和将a单独作为结构体变量的时候一样(那样方便赋值运算)

 

剩下的和上面的规则相同;

 

所以:B的大小就是24(struct A)+ 1(char) +7(pad) = 32字节;

 

不知正确与否?还请诸位评判。

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值