c/c++结构体对齐小结...
时间:2010-08-06 来源:hexiankang1984
因为我看C++对象模型的时候,遇到了几个内存布局都是有关于对齐的一些细节,故此对结构体对齐再做一份小结,有人说:结构体对齐这个东西是依赖于编译器的,因此不用去研究,真的嘛?
也许是,也许不是,要看你是做那个行业的了,如果你是做系统地层,网络通讯,嵌入式系统的,一个字节的节省,也许对你是很大的期望呢。虽然具体的对齐方式是因编译器而异,但是对齐的基本原理是不变的,那个原理也许能指导我们编写程序的时候按照某个原则去进行。
不过,既然你用到了C或者C++,就多数是和系统底层有缘之人了,你说是嘛?呵呵。
现在先说在windows x86 32位机子下的MS vs2005编译器(就是:cl.exe for x86)下的对齐规则:
比如以下的结构体定义:
struct A
{
int i;
double d;
char c;
};
问sizeof(struct A)在vs2005的大小?
现在说一下cl.exe(就是微软vs2005的编译器进程)在默认情况下是怎么做的:
1、对齐量的确定:找到A中最大的基本类型成员的大小,在本例中是8(double的大小).
2、当定义一个结构体变量struct A aA; 的时候,aA的起始地址要被由1确定的对齐量整除,在这个例子里,aA的起始地址一定要能被8整除)
2、然后开始分配int i,4字节的空间;再分配double d;注意double 是8字节,所以要分配在被8整除的地方,因此int i后面空了4字节填充;
3、然后,分配char c;1字节,这个时候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;的大小) + 8(double 的大小) + 1(char 的大小) + 3 (为了4字节填充而补充的字节) = 16字节;
至于gcc的结构体变量的首地址分配的特征一时也找不到,还望各位多多指教。谢谢。
最后,如果定义一个没有任何成员的结构体,struct A{}; 该大小是多少呢?是1字节。如果定义了两个结构体变量struct A a1, a2; 1字节的填充能够使a1和a2的地址区分开来!
还有其他的编译器和操作系统就不是我所能知的了。
那么,这些规则也许不尽相同,但是给了我们一个编程时候的注意点,就是:
定义结构体的时候,成员最好能从大到小来定义,那样能相对的省空间。(至少不会比别的顺序差,一般情况下哈。)
比如以上的结构体,如果能这样定义:
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字节;
不知正确与否?还请诸位评判。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiangnanyouzi/archive/2009/01/16/3793864.aspx