内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。
对齐原因
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
对齐规则
#pragma pack(n)
编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。
n:可选参数;指定packing的数值,以字节为单位;默认数值是8,合法的数值分别是1、2、4、8、16。
代码示例
使用默认##pragma pack(n)
#include <iostream>
using namespace::std;
//#pragma pack (n)
class Csize{
public:
int x;
char y;
void print();
};
void Csize::print()
{
cout << sizeof(Csize) << endl;
}
int main(int argc,char *argv[])
{
Csize a;
a.print();
return 0;
}
此时输出结果为8,即类Csize的长度为8。当程序未设定#pragma pack (n)时,默认n=8,即编译器执行8字节对齐。而类中最大数据元素为int型,占4个字节,此时执行较小的,也就是4字节对齐方式。类Csize中其他类型,如本例中的char类型只有1个字节,在执行4字节对齐的情况下,后面两个字节自动补齐(1+3),不添加任意数据。所以类Csize长度为4+(1+3)=8。
使用#pragma pack (2)
#include <iostream>
#pragma pack(2)
using namespace::std;
class Csize{
public:
int x;
char y;
void print();
};
void Csize::print()
{
cout << sizeof(Csize) << endl;
}
int main(int argc,char *argv[])
{
Csize a;
a.print();
return 0;
}
此时输出结果为6。由于#pragma pack (2),设定n=2,编译器执行2字节对齐。此时int型被拆分成两个部分,均为2字节,而char型本身为1字节,但是自动补全1个字节。所以2+2+(1+1)=6,即类Csize的长度为6。
注意:#progma pack (n)中,n只能取合法的计算机数值,即2^n。否则会出现警告,如:warning: alignment must be a small power of two, not 3 [-Wpragmas]