我曾经在文章C++结构体字节对齐https://blog.csdn.net/iaibeyond/article/details/48971563
讨论过C++的相关字节对齐问题。C++11带来了两个关键字alignof和alignas。
alignof(Type),用于获取类型的对齐字节数。
alignas(number) Type,用于改变目标类型的对齐字节数。
它们直观的区别是alignof是get,alignas是set。有些同学在开始记忆的时候可能会混淆alignof和alignas,一个简单的记忆方式是把单词拆开理解,align of Type,即Type的对齐字节数;align as number ,即把字节数当做(as) number。这样就不会记错了。
关于alignof格外要注意的一点是,它只能用于操作类型,不能操作变量。sizeof则不同,既可以操作类型,也可以操作变量。
struct A
{
int a;
int b;
A()
{
cout << "alignof(int) = " << alignof(int) << endl;
cout << "alignof(b) = " << alignof(b) << endl; //编译错误!alignof只能操作类型,不能操作变量!
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(b) = " << sizeof(b) << endl; //OK!sizeof既能操作类型,也能操作变量!
}
};
alignas,主要有以下3个应用场景
1、修改结构体的对齐依据。
struct stTestAlign
{
char a;
char b;
stTestAlign()
{
cout << "sizeof(stTestAlign) =" << sizeof(stTestAlign) << endl; //2
cout << "alignof(stTestAlign) =" << alignof(stTestAlign) << endl; //1
}
};
stTestAlign在没有使用alignas的情况下,sizeof=2,alignof=1
struct alignas(4) stTestAlign
{
char a;
char b;
stTestAlign()
{
cout << "sizeof(stTestAlign) =" << sizeof(stTestAlign) << endl; //4
cout << "alignof(stTestAlign) =" << alignof(stTestAlign) << endl; //4
}
};
现在使用alignas(4)指定stTestAlign对齐依据为4,则sizeof=4,alignof=4。
2、修改结构体内部变量的对齐依据。
struct stTestAlign
{
char a;
alignas(4) char b;
stTestAlign()
{
cout << "sizeof(stTestAlign) =" << sizeof(stTestAlign) << endl; //8
cout << "alignof(stTestAlign) =" << alignof(stTestAlign) << endl; //4
}
};
我们要求char b的对齐依据为4,那么最终 sizeof(stTestAlign)=8,alignof(stTestAlign)=4
这里有个问题,如果变量添加了alignas,结构体也添加了alignas,那么结构体的最终对齐依据是谁呢?
这个其实和默认的对齐规则一样,两者取其大。
struct alignas(2) stTestAlign
{
char a;
alignas(4) char b;
stTestAlign()
{
cout << "sizeof(stTestAlign) =" << sizeof(stTestAlign) << endl; //8
cout << "alignof(stTestAlign) =" << alignof(stTestAlign) << endl; //4
}
};
3、修改单独变量的对齐依据。
这个其实和第2条类似,第2条的变量在结构体内部,而这里变量不在结构体内。
alignas(number) Type variable;意思是:给变量variable分配地址的时候,它的地址要是number的整数倍,即地址要对齐number。
int a;
cout << (int)(&a) % 16 << endl;
int默认以4对齐,则a的地址对16取模,可能是0 4 8 12。
alignas(16) int a;
cout << (int)(&a) % 16 << endl;
此时我们强制a向16对齐,则a的地址对16取模,只能是0,因为它的地址一定是从16的整数倍开始的嘛!
需要注意的有: