C语言结构体内存对齐(计算结构体内存大小)
2016-02-17 00:53
197 查看
C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐?
对齐原则
方法一
有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下):原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
方法二
linux 默认#pragma pack(4),window 默认#pragma pack(8)。
pack的值越小,越节省内存,不过跑的就越慢。
#pragma pack(4)//设定为4字节对齐
取pack的值,和 结构体中最大的值 比较。
选择最小的值 为K,K的倍数为外对齐原则。
K和每一个成员的大小比较,取最小的值为内部对齐原则。
所谓对齐,就是 内存首地址 是这个数的 倍数。
举例
我们看下面几个例子,通过实例来加深理解。例1:
struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; //这个很好理解,三个short都为2。 sizeof(B) = 8; //这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。
例2:
struct A{ int a; char b; short c; }; struct B{ char b; int a; short c; }; sizeof(A) = 8; //int为4,char为1,short为2,这里用到了原则1和原则3。 sizeof(B) = 12; //是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。
深究一下,为什么是这样,我们可以看看内存里的布局情况。
(其中星号*表示填充的字节。)
A的内存布局:
a | b | c |
---|---|---|
1111 | 1* | 11 |
b | a | c |
---|---|---|
1*** | 1111 | 11** |
B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。
再看一个结构中含有结构成员的例子:
例3:
struct A{ int a; double b; float c; }; struct B{ char e[2]; int f; double g; short h; struct A i; }; sizeof(A) = 24; //这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。 sizeof(B) = 48;
B的内存布局:
e | f | g | h | i |
---|---|---|---|---|
11** | 1111 | 11111111 | 11****** | 1111**** 11111111 1111**** |
以上讲的都是没有#pragma pack宏的情况,如果有#pragma pack宏,对齐方式按照宏的定义来。比如上面的结构体前加#pragma pack(1),内存的布局就会完全改变。sizeof(A) = 16; sizeof(B) = 32;
有了#pragma pack(1),内存不会再遵循原则1和原则3了,按1字节对齐。没错,这不是理想中的没有内存对齐的世界吗。
A的内存布局:
a | b | c |
---|---|---|
1111 | 11111111 | 1111 |
e | f | g | h | i |
---|---|---|---|---|
11 | 1111 | 11111111 | 11 | 1111 11111111 1111 |
相关文章推荐
- c语言笔试题总结2
- 程序设计第三次作业---C++计算器雏形
- c++编译器何时会生成默认构造函数
- 折半查找法
- hdu 5470 Typewriter
- 冒泡、鸡尾酒、选择、插入、归并、快速排序的C++程序
- C语言深度解剖学习笔记
- C++纯虚函数与抽象类
- C++虚析构函数
- x265-1.8版本-encoder/weightPrediction.cpp注释
- c++对象内存布局模型
- C++语言之类class
- C++语言之类class
- 杂谈之C++中的“错误”处理
- C++语言之类class
- c++成员函数存储方式
- C语言基本概念以及关键字与标识符
- C++静态关联与动态关联
- 编程题#10:输出指定结果二(C++程序设计第10周)
- C语言 goto语句