C++11的alignof和alignas

我曾经在文章C++结构体字节对齐icon-default.png?t=M276https://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的整数倍开始的嘛!

需要注意的有:

  1. alignas只能往大对齐,不能往小对齐,如果类型本身的对齐依据是4,那么alignas(2)则不起效!即它不能起到#pragma pack的作用!如果想往小对齐,只能使用pragma pack。
  2. __declspec(align(4))也是指定往大对齐,它和alignas(4)有什么区别?alignas是C++语言级别的标准,而__declspec则是Microsoft自己添加的扩展。它们在使用方式上有区别,但起到的作用是一样的,都是为了往大对齐。既然已经有一个能起到往大对齐的__declspec(align())了,为什么还要加个alignas?猜测原因是为了提高使用的精准性,__declspec有很多用途,__declspec(align())只是它的用途之一,而加了alignas则专门用于字节对齐。这个出发点和C++11引入匿名命名空间有点像,是为了取代static,成为专门处理文件静态变量的手段;而alignas则是专门处理字节对齐的手段。

你可能感兴趣的:(C++,c++)