C/C++ 内存中的数据对齐

      数据对齐,就是 数据所在的内存地址必须是该数据长度的整数倍,以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

    输出结果:    

猜你喜欢

转载自blog.csdn.net/zgcjaxj/article/details/105929486