1、现象
先看一段代码:
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也是如此,这就涉及到一个概念:内存对齐。
2、内存对齐
(1)什么是内存对齐?
看到的一句说明:数据项仅仅能存储在地址是数据项大小的整数倍的内存位置上。
(2)为什么要内存对齐?
1> 硬件原因:一些硬件平台必须要求内存对齐,否则抛出异常;另外涉及到不同平台的移植问题。
2> 软件原因:对齐后访问效率更高。
3、C++98/03 内存对齐实现
此情况下主要是由编译器实现,不同编译器有不同方法。
(1)MSVC
__declspec(align(#)) //其#的内容可以是预编译宏,但不能是编译期数值
#progma pack
__alignof
(2)gcc
__attribute__((__aligned__((#))))
__alignof__
4、C++11内存对齐实现
(1)C++11新引入操作符alignof,对齐描述符alignas,基本对齐值alignof(std::max_align_t)
alignas可以接收常量表达式和类型作为参数,可以修饰变量、类的数据成员等,不能修饰位域和用register申明的变量。一般往大对齐。直接看一段代码:
struct s1
{
char s;
int i;
};
struct s2
{
int i;
double d;
};
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
5、实例
#include <iostream>
//对齐支持
//C++11标准定义alignof来查看数据的对齐方式
//Microsoft定义为__alignof来查看数据的对齐方式
struct EmptyStruct{};
class EmptyClass{};
class EmptyClass1;
struct HowManyBytes
{
char a;
int b;
};
struct ColorVector1
{
double r;
double g;
double b;
double a;
};
//C++11标准提供修饰符alignas设定struct/class/union的对齐方式
//Microsoft使用_declspec(align(#))来设定struct/class/union对齐方式
struct _declspec(align(32)) ColorVector2 //直接将ColorVector设定在32字节的地址边界上,其起始地址必须是32的倍数
//等价_declspec(align(32)) struct ColorVector
{
double r;
double g;
double b;
double a;
};
int main()
{
std::cout << "sizeof(EmptyStruct): " << sizeof(EmptyStruct) << std::endl; //1
std::cout << "sizeof(EmptyClass): " << sizeof(EmptyClass) << std::endl; //1
std::cout << "__alignof(EmptyClass): " << __alignof(EmptyClass) << std::endl; //1
//error,类型不完整,编译失败
//std::cout << "__alignof(EmptyClass1): " << __alignof(EmptyClass1) << std::endl;//1
std::cout << "sizeof(char): " << sizeof(char) << std::endl; //1
std::cout << "sizeof(int): " << sizeof(int) << std::endl; //4
std::cout << "sizeof(HowManyBytes): " << sizeof(HowManyBytes) << std::endl; //8
std::cout << "offset of char a: " << offsetof(HowManyBytes, a) << std::endl; //0
std::cout << "offset of int b: " << offsetof(HowManyBytes, b) << std::endl; //4
std::cout << "__alignof(HowManyBytes): " << __alignof(HowManyBytes) << std::endl; //4
std::cout << "__alignof(ColorVector1): " << __alignof(ColorVector1) << std::endl; //8
std::cout << "__alignof(ColorVector2): " << __alignof(ColorVector2) << std::endl; //32
std::cout << "sizeof(ColorVector2): " << sizeof(ColorVector2) << std::endl; //32
std::cout << "in ColorVector1 offset of double r: " << offsetof(ColorVector1, r) << std::endl; //0
std::cout << "in ColorVector1 offset of double g: " << offsetof(ColorVector1, g) << std::endl; //8
std::cout << "in ColorVector1 offset of double b: " << offsetof(ColorVector1, b) << std::endl; //16
std::cout << "in ColorVector1 offset of double a: " << offsetof(ColorVector1, a) << std::endl; //24
std::cout << std::endl;
std::cout << "in ColorVector2 offset of double r: " << offsetof(ColorVector2, r) << std::endl; //0
std::cout << "in ColorVector2 offset of double g: " << offsetof(ColorVector2, g) << std::endl; //8
std::cout << "in ColorVector2 offset of double b: " << offsetof(ColorVector2, b) << std::endl; //16
std::cout << "in ColorVector2 offset of double a: " << offsetof(ColorVector2, a) << std::endl; //24
int a;
long long b;
auto &c = b;
char d[1024] = { 0 };
//对内置类型
std::cout << __alignof(int) << std::endl; //4
//对变量、引用或者数组
std::cout << __alignof(a) << std::endl //4
<< __alignof(b) << std::endl //8
<< __alignof(c) << std::endl //8 引用与其引用的数据对齐值相同
<< __alignof(d) << std::endl; //1 数组的对齐值由其元素决定
return 0;
}