目录
本文记录alignas关键字,同时介绍alignof和sizeof。
1 预备知识
如有此知识点的同学,请绕过,直接看第2章。
字节对齐主要是为了提高内存的访问效率,比如intel 32位cpu,每个总线周期都是从偶地址开始读取32位的内存数据,如果数据存放地址不是从偶数开始,则可能出现需要两个总线周期才能读取到想要的数据,因此需要在内存中存放数据时进行对齐。
struct有自己的对齐规则,但是也可以加入#progma pack (value)来进行管理(请看1.2节)
1.1 struct对齐规则
规则一
struct A{
char a;
int b;
double c;
};
sizeof(A) = 16;
- 规则一:结构体中元素是按照定义顺序一个个放到内存中的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己大小的整数倍上开始(以结构体变量首地址为0计算)。
规则二
struct A{
char a;
double c;
int b;
};
仅仅修改了结构体成员变量的顺序 ,但sizeof(A) = 24;
- 规则二:在按照第一规则进行内存分配后,需要检查计算分配的内存大小是否为所有成员中大小最大的成员的大小的整数倍,若不是,则补齐为它的整数倍。
- 如果出现指针的时候,其实只需要知道指针的地址就是4个字节就可以了。
- 如果出现指数组的时候,c++里面数组名字其实也就是指针的意思,按照指针去理解就可以了
- 如果结构体嵌套结构体呢?
规则三(也是对规则一和二的提升,重要请看)
- 规则三:如果一个结构体B里嵌套另一个结构体A,则结构体A应从offset为A内部最大成员的整数倍的地方开始存储。(struct B里存有struct A,A里有char,int,double等成员,那A应该从8的整数倍开始存储。),结构体A中的成员的对齐规则仍满足规则一、规则二。
typedef struct TEST{
int na;
char cb;
char cc;
int nd;
char cf;
struct TT{
int ng;
long long llh;
}tt;
char ci;
}test;
1.2 struct不对齐方法
下面我们使用预编译指#pragma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。
#pragma pack (2) /*指定按2字节对齐 ~start*/
struct C {
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐 ~ end */
sizeof( C) = 8 b 为char 一个字节,但指定2字节 ;int 为4字节,指定2字节无效;short为2字节;共8字节。
不字节对齐的话 就设置#pragma pack(1)
修改对齐值为1:
#pragma pack (1) /*指定按1字节对齐*/
struct D{
char b;
int a;
short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(D) = 7。
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
还可以设置编译环境中的设置 :
(VS2005下,右击项目-属性-配置属性-C/C++-代码生成-结构成员对齐-选“1字节(/Zn1):”(即禁止内存对齐),默认是使用默认值,即按照结构中占用空间最大的成员进行对齐。
2 alignas 关键字
此关键字为c++11之后引入,有部分内容其实和#pragma pack (value) 重叠;
alignas关键字用来设置内存中对齐方式,最小是8字节对齐,可以是16,32,64,128等
struct test1{
char c;
int i;
double d;
};
struct alignas(8) test2{
char c;
int i;
double d;
};
struct alignas(16) test3{
char c;
int i;
double d;
};
struct alignas(32) test4{
char c;
int i;
double d;
};
sizeof(test1) = 16 ,sizeof(test2) = 16 ,sizeof(test3) = 16 ,sizeof(test4) = 32;
计算方法就是对齐数的整数倍,比如test4 32位对齐,实际数据大小不到32字节,但内存还是占用32字节。实际数据大于32字节小于64字节,内存占用64字节
这里test4 不够32字节,地址下标0 ~ 4 ~8 ,后面补齐 16位 ,直至32字节;
alignof(test1) = 8 ,alignof(test2) = 8 ,alignof(test3) = 16 ,alignof(test4) = 32;
避免出现此种情况:
struct alignas(8) s{}
struct alignas(1) U{s s;} // BAD