字节对齐问题在面试笔试中经常碰到,自己也在这里经常碰到坑,今天索性把这方面搞清楚,记录自己这方面的学习过程。
大端小端法
机器的大端小端问题一直是一个常考的点,并且struct的内存布局问题和这个大端小端有很大关系,这里先看下机器的大端小端问题:
下面通过一张图来说明问题,假如一个变量int x的值为0x12345678,当在不同的机器上存储顺序是不同的
可以看到,大端机器上低地址存储的是高位,小端则恰恰相反。用一个C语言程序来测试你的机器是大端还是小端的好的方式如下:
show_bytes()
{
int x = 0x12345678;
unsigned char *p = (unsigned char*)&x;
int i = 0;
for(i = 0; i < sizeof(int);i++)
{
printf("%.2x",p[i]);
}
printf("\n");
}
这段代码可以看出当前系统是大端还是小端,在我的机器上显示的是78563412,因此我的电脑是小端模式。
struct 与union的对齐规则
- struct或者union的数据成员对齐规则:第一个放在offset位置为0处,从第二个开始,该元素与前一个元素之间的填充是由该元素字长与#pragma pack(k)(k=1,2,4,8,16)中的k之间的小者来决定。如果本身为两者之间的小者的整数倍,则不进行填充。即除去第一个元素,其余的元素的开始位置是由两者之间的小者的整数倍来决定的
- 整体填充完毕后,该struct整体大小是由pack(k)指定的k与数据元素里面最大字长之间的小者决定。
下面举几个例子来说明字节对齐遵循的规则
#pragma pack(k)//k=1,2,4,8,16
struct S4 {
char x1;
double x2;
short x3;
float x4;
char x5;
};
cout<< sizeof(S4) << endl;
可以打印k分别等于1,2,4,8,16时S4的占用的大小空间,可以得到的结果分别为
16
18
24
32
32 //和k为8的结果相同
k为1的时候,此时不进行对齐,因此为所有变量的字长之和。下面从k为2的时候开始分析
- k = 2 时,第一个元素从offset为0的地址开始,第二个元素是double占8个字节,和当前k=2对比,2较小,又因为第一个元素是char,只占用一个字节,因此第二个元素和第一个元素之间需要达到2的倍数,需要填充1个字节;再看x3,x3占用2字节和k=2相等,而x1和x2已经占用了10字节,为2的倍数,因此x3和x2之间不填充字节;再看x4,占用4字节,比k=2大,而前三个元素已经12字节,为2的倍数,因此不需要填充。最后一个元素也不用填充。整体为18字节。整体18个字节,是2的倍数,因此最后一个元素不需要填充。下面是内存布局图:
其它的情况和这个类似,可以对比着画出来。