字节对齐的意义:
字节对齐是计算机系统的存储器与处理器数据交换规则。数据在存储器上存储方式决定了处理器的读取速度,对齐限制为双方制定了一个约定,简化了双方的硬件接口设计。
假如处理器一次从存储器中取4个字节,处理器每次都会在地址为4K(4的整数倍)的地址开始读取数据。
举个例子:
struct T1
{
char c;
short s;
int i;
}
sizeof(T1)结果是8字节,数据在内存中的分布如下:

如果没有字节对齐的话,需要把变量s和i前移一个字节,
而目前处理器是以4字节为单位从存储器中读取数据,后果就是读取变量i时需要读两次内存,因为变量i分布在0-3和4-7两个单元上,
这是计算机在空间和时间的博弈,损失空间换取时间。
一个结构体在内存中占多少字节?
按照字节对齐的原则,K字节的对象的地址必须是nK,结构体中的变量按照顺序,依次找到符合自己的位置(short要求2k,int要求4k,double要求8k。。。),中间没有用到的字节使用占位符,也要算到结构体的长度中。
在这里需要解释windows严格要求k字节对象的地址必须是k的倍数,linux在处理8字节的double变量时,采用了4字节对齐。
————————————————————————————————————————————————————————————————————————
除了系统提供的规则,我们可以在自己的程序制定字节对齐规则。
使用预编译指令#pragma pack (value)告诉编译器对齐数value,如下
#pragma pack(4) struct T2 { short s; int i; } #pragma pack()
按照4字节对齐之后,结构体大小为8字节,结构体在内存分布如下:
#pragma pack(2)
struct T3
{
short s;
int i;
}
#pragma pack()
按照2字节对齐之后,结构体大小变为6字节,结构体在内存中分布如下:
需要注意的是对齐规则只对 value>sizeof(成员)的结构体成员生效,例如pack(4)并不会改变short成员存储在2K地址的规则,但是double就会从4K的地址开始存放。
使用#pragma pack编译选项应该清楚的意识到,它会为程序带来什么影响。
如果pack(1),那么结构体会依次排布占满所有的地址,这样做的好处是使用最小的地址空间,但是这样处理器在读取结构体时效率最低。
字节对齐方式与处理器地址宽度相同,这时处理器读取结构体效率最高,吞吐率也最大。
————————————————————————————————————————————————————————————————————————
一些建议:
1.定义结构体时,按照变量占用空间的大小,由大到小确定结构体中变量的顺序,这样可以既节省空间,又不损失效率。
2.网络中传递数据时,最好双方约定字节对齐方式,因为不同系统之间的字节对齐方式有可能不同。
3.当结构体中嵌套结构体时,最好不要让内存结构体把外层结构体分隔开,这样的话外层结构体字节对齐方式会被分为两种。