-
1.硬件要求: 许多计算机体系结构(例如x86、ARM等)要求访问特定数据类型的数据时,数据的地址必须是其大小的倍数。例如,对于4字节大小的整数,在x86架构中,它必须位于内存中4字节的整数倍地址上。如果未对齐,处理器可能需要额外的指令来访问数据,这会降低性能。
-
2.访问效率: 当数据按照正确的对齐方式存储时,处理器可以更快地访问内存,因为它可以通过简单的内存地址计算来定位数据,而无需额外的处理。这对于提高程序的整体性能至关重要,特别是对于大规模的数据处理任务。
-
3.节省内存空间: 对齐可以带来额外的好处,即节省内存空间。当结构体或对象中的数据成员按照最大对齐要求排列时,可以减少内存碎片和填充字节的数量,从而节省内存空间。这对于内存受限的系统尤其重要。
-
4.与硬件接口的兼容性: 某些硬件接口可能要求数据以特定的对齐方式传输。如果数据未对齐,则可能无法与这些接口进行正确的通信,从而导致数据传输失败或错误。
在C语言中,可以通过以下方式来实现字节对齐:
结构体对齐: 在定义结构体时,编译器会根据平台的要求对结构体进行对齐。可以使用编译器指令来指定结构体的对齐方式,常用的指令包括#pragma pack
和__attribute__((aligned))
。
#pragma pack(push, 1) // 设置对齐方式为1字节对齐
struct MyStruct {
char a;
int b;
float c;
};
#pragma pack(pop) // 恢复默认对齐方式
变量对齐: 除了结构体外,单个变量也可以通过__attribute__((aligned))
指定对齐方式。
int __attribute__((aligned(16))) aligned_variable;
数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值
struct B
{
char b;
int a;
short c;
};
假设B从地址空间0x0000开始排放。
该例子中没有定义指定对齐值,默认为4。
第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,
所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0。
第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,
所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,
复核0x0004%4=0,且紧靠第一个变量。
第三个变量c,自身对齐值为2,所以有效对齐值也是2,
可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。
所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐
值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对
齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。
所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,
sizeof(struct B)=12;其实如果就这一个就来说它已将满足字节对齐了,
因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,
是因为编译器为了实现结构数组的存取效率。
#pragma pack (2) /*指定按2字节对齐*/
struct C
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,
假设C从0x0000开始,那么b存放在0x0000,符合0x0000%1=0。
第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,
所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续字节中,符合0x0002%2=0。
第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放。
在0x0006、0x0007中,符合0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。
又C的自身对齐值为4,所以C的有效对齐值为2。又8%2=0,C只占用0x0000到0x0007的八个字节。
所以sizeof(struct
C)=8.