一 现象
先看一段代码:
struct s1
{
char s;
int i;
};
struct s2
{
int i;
double d;
};
cout << "-------basic type" << endl;
cout << "sizeof(char) " << sizeof(char) << endl;
cout << "sizeof(int) " << sizeof(int) << endl;
cout << "sizeof(double) " << sizeof(double) << endl;
cout << endl;
cout << "-------struct" << endl;
cout << "sizeof(s1) " << sizeof(s1) << endl;
cout << "sizeof(s2) " << sizeof(s2) << endl;
结果如下:
不同机器环境,可能结果不同,但不影响说明问题。例如,结构体s1中包含一个char和int,那么s1的大小应该是5,但结果是8,s2也是如此,这就涉及到一个概念:内存对齐。
二 内存对齐
1 什么是内存对齐?
看到的一句说明,“数据项仅仅能存储在地址是数据项大小的整数倍的内存位置上”。
2 为什么要内存对齐?
(1)硬件原因,一些硬件平台必须要求内存对齐,否则抛出异常;另外涉及到不同平台的移植问题。
(2)性能原因,对齐后访问效率更高。
三 C++11 内存对齐实现
1 C++11 新引入操作符alignof, 对齐描述符alignas,基本对齐值 alignof(std::max_align_t)
alignas可以接受常量表达式和类型作为参数,可以修饰变量、类的数据成员等,不能修饰位域和用register申明的变量。一般往大对齐。
直接看一段代码(结合上一段代码):
struct s3
{
char s;
double d;
int i;
};
struct s11
{
alignas(16) char s;
int i;
};
struct s12
{
alignas(16) char s;
int i;
};
// alignof
cout << "-------------------alignof---------------------" << endl;
// 基本对齐值
cout << "alignof(std::max_align_t) " << alignof(std::max_align_t) << endl;
cout << endl;
cout << "-------basic type" << endl;
cout << "alignof(char) " << alignof(char) << endl;
cout << "alignof(int) " << alignof(int) << endl;
cout << "alignof(double) " << alignof(double) << endl;
cout << endl;
cout << "-------struct" << endl;
cout << "alignof(s1) " << alignof(s1) << endl;
cout << "alignof(s2) " << alignof(s2) << endl;
cout << "alignof(s3) " << alignof(s3) << endl;
cout << endl;
cout << endl;
// alignas
cout << "-------------------alignas---------------------" << endl;
cout << "alignof(s1) " << alignof(s1) << endl;
cout << "alignof(s11) " << alignof(s11) << endl;
cout << "alignof(s12) " << alignof(s12) << endl;
cout << "sizeof(s1) " << sizeof(s1) << endl;
cout << "sizeof(s11) " << sizeof(s11) << endl;
cout << "sizeof(s12) " << sizeof(s12) << endl;
结果如下:
2 C++11还新增了几个内存对齐的函数,每个函数有特定作用,此处不展开。
std::alignment_of
std::aligned_storage
std::max_align_t
std::align
四 C++98/03 内存对齐实现
此情况下主要是由编译器实现,不同编译器有不同方法。
1 MSVC
__declspec(align(#)),其#的内容可以是预编译宏,但不能是编译期数值
#progma pack
__alignof
2 gcc
__attribute__((__aligned__((#))))
__alignof__