|
问题引入:
定义一个结构体的一般形式为:
- struct 结构体名
- {
- //类型说明符 成员名;
- };
复制代码
例如有如下结构体:
- struct Stu
- {
- int id;
- char sex;
- float hight;
- };
复制代码
那么一个这样的结构体变量占多大内存呢?也就是:
会输出什么?
在了解字节对齐方式之前想当然的会以为:sizeof(Stu) = sizeof(int)+sizeof(char)+sizeof(float) = 9
然而事实并非如此!
字节对齐原则
在系统默认的对齐方式下:每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍,且最终占用字节数为成员类型中最大占用字节数的整数倍。
在这个例子中,id 的偏移量为 0(0=4*0),sex 的偏移量为 4(4=1*4),hight 的偏移量为 8(8=2*4),此时占用 12 字节,也同时满足 12 = 3*4,所以 sizeof(Stu) = 12
(1)出现继承关系时:
- struct A{
- int a;
- char b;
- };
- struct B:A{
- char c;
- int d;
- long long e;
- };
复制代码
基类的成员总是在派生类的前面。而且即使有字节对齐,基类对齐后派生类的成员不会占用基类填充的字节,即计算好基类所占字节数后,这些字节只能由基类拥有,不能被派生类的成员占用(即char b后面有3字节的填充,之后才有char c)在派生类中成员的分布只需满足每个变量起始字节序号为该类型所占字节数的整数倍且最终大小为占用字节数最大的类型对应的字节数的整数倍。
排列如下:
- /*
- 0 4 8 12 16 24
- | | | | | |
- aaaab---c---ddddeeeeeeee
- */
复制代码
(2)出现关联关系时:
必须满足:
1.结构体/类与结构体/类之间不会共用自动补齐的内存,即一个结构体变量/对象对齐之后填补的内存不允许被其他变量/对象占用;
2.结构体的起始字节位置必须是该结构体中所占字节数最大的变量的字节数的整数倍;
3.最终所占字节数必须是最大所占字节数最大的变量的字节数的整数倍。
(3)出现强制对齐方式时:
当然,有时候考虑到其他特殊用途,使用 #pragma pack(n) 来设定以n字节对齐的方式(n可取2的较小次幂,即 1,2,4,8,具体取值范围以及默认值与所使用的编译器有关。笔者所测试的环境下vs/vc默认为8,gcc默认为4)。
n字节对齐就是说变量存放的起始地址的偏移量有两种情况:
第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式;
第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。
比如有以下代码:
- #pragma pack(push) //保存对齐状态
- #pragma pack(4) //设定为4字节对齐
- struct Test
- {
- char c1;
- double d;
- int i;
- char c2;
- };
- #pragma pack(pop) //恢复对齐状态
复制代码
这时候编译器就会被迫使用我们约定的字节对齐方式,即4字节对齐,因此c1占4字节,d占8字节,i占4字节,c2占4字节,共20字节;
如果我们没有设置字节对齐方式,仍然使用默认对齐的话,这里sizeof(Test) = 24。
注:以上测试效果及完整代码见附件:
code.cpp
(4.06 KB, 下载次数: 4)
|
上一篇: 函数调用的开销下一篇: vs2008 单文档中 VC 如何实现当鼠标移动到一个菜单上时,任务栏有相应的提示
|