数据对齐,就是 数据所在的内存地址必须是该数据长度的整数倍,以64bit CPU为例,比如short变量的内存起始地址必须是2的整数倍,int/float必须是4的整数倍,long/double/指针类型 必须是8的整数倍,long double必须是16的整数倍。Bool/char为1byte,起始地址就任意了。
对于一个结构体来说( class或struct) ,总结对齐原则就是:结构体的长度 一定是最长的数据元素的整数倍。
数据对齐的意义:一句话就是,这样做会使得CPU的访存效率更高,性能更优。现代CPU在访存时一般都会一次性取4 、8、 16byte的数据。比如CPU要访问一个int变量,如果起始地址为 0x00001,则需要先以0x00000为地址读4byte,获取其中的3byte,然后再以0x00004为起始地址读4byte,获取其中的1byte;如果起始地址对齐到4的倍数,则一次访存即可。
以下是几个 结构体数据对齐的例子,class C_中的c1是static变量,在全局变量数据区,sizeof计算的是栈中的分配的大小,所以sizeof C只有4byte。struct G_中有long double,超出了CPU的位数,有本书讲到,如果结构体内存在长度大于处理器位数的元素,那么以处理器位数 为对齐单位。但实际的打印结果却是占32byte,这块还没有找到权威书籍来澄清这一现象,姑且按照实际结果来,认为这本书中的解释错误。
// data alignment
#include <iostream>
using namespace std;
struct A_ {
short a1;
short a2;
short a3;
} A;
class B_ {
public:
bool b1;
bool b2;
int b3;
} B ;
class B1_ {
public:
bool b1;
int b3;
bool b2;
} B1 ;
class C_ {
int c1;
//static variable save in global area,
// sizeof can't get its size
static int c2;
} C ;
struct D_ {
char d1[3];
int d2;
float d3;
double d4;
} D;
struct E_ {
char e1;
int e2;
char e3;
double e4;
} E;
struct E1_ {
char e1;
char e3;
int e2;
double e4;
} E1;
struct G_ {
int g1; // 4byte
long double g2; // 16byte
} G;
int main(int argc, char** argv)
{
cout <<" sizeof (A) "<<dec<<sizeof (A)<<endl;
cout <<" sizeof (B) "<<dec<<sizeof (B)<<endl;
cout <<" sizeof (B1) "<<dec<<sizeof (B1)<<endl;
cout <<" B1.b1 addr "<<hex <<& (B1.b1)<<endl;
cout <<" B1.b3 addr "<<hex <<& (B1.b3)<<endl;
cout <<" B1.b2 addr "<<hex << & (B1.b2)<<endl;
cout<<endl;
cout <<" sizeof (C) "<<dec<<sizeof (C)<<endl;
cout <<" sizeof (D) "<<dec<<sizeof (D)<<endl;
cout <<" sizeof (E) "<<dec<<sizeof (E)<<endl;
// &E.e1 return char*, if use cout, need cast type to void*
// https://blog.csdn.net/pianzhizhixing/article/details/87359125
cout <<" E.e1 addr "<<hex <<(void *)(&E.e1)<<endl;
cout <<" E.e2 addr "<<hex << & (E.e2)<<endl;
cout <<" E.e3 addr "<<hex <<(void *)(&E.e3)<<endl;
cout <<" E.e4 addr "<<hex << & (E.e4)<<endl;
cout<<endl;
cout <<" sizeof (E1) "<<dec<<sizeof (E1)<<endl;
cout <<" E1.e1 addr "<<hex <<(void *)(&E1.e1)<<endl;
cout <<" E1.e3 addr "<<hex <<(void *)(&E1.e3)<<endl;
cout <<" E1.e2 addr "<<hex << & (E1.e2)<<endl;
cout <<" E1.e4 addr "<<hex << & (E1.e4)<<endl;
cout<<endl;
cout <<" sizeof (G) "<<dec<<sizeof (G)<<endl;
cout <<" G.g1 addr "<<hex << & (G.g1)<<endl;
cout <<" G.g2 addr "<<hex << & (G.g2)<<endl;
return 0;
}
int型变量可以直接使用“&”获取地址,而char型变量取不行。
原因:&a是一个char*变量,应该指向一个字符串,并且字符串需要以终止符(“\0”)结尾,但&a却没有终止符,所以会输出后面的乱码
解决办法:1. 可以用printf代替cout输出;2. 将&a强制转换成(void *)&a
原文链接:https://blog.csdn.net/pianzhizhixing/article/details/87359125
输出结果: