内存对齐(补齐)

来源:互联网 发布:kong audio mac 编辑:程序博客网 时间:2024/05/16 16:14
 首先,来解释一下为什么要内存对齐(或者称补齐)

一个原因是,实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数。

另一个原因是,可以提升读取或写入数据的速度,减少读取或写入的次数。

         接下来,来谈谈内存对齐(补齐)的准则

以结构体struct、类class里面的最宽的数据类型为对齐模数,其余数据类型依照该模数进行对齐(补齐),得到的sizeof的值,应该是对齐模数的倍数

例子:

class X

{                                        

  public:

            double a;

            int b;

           short c;

           char d;

};

以类X里的double类型为对齐模数,double类型是8个字节,int、short、char这三个类型的字节加起来总共是7个字节,按照double类型的8个字节进行补齐,补齐后的sizeof(X)的值就是16,

要是现在把double类型的位置改变一下,放在int和short的中间,或者放在short和char的中间,sizeof(X)的值还会是16吗?

呵呵,显然不是16,那会是多少呢?

double类型的上面的int类型,进行补齐,再把double类型的下面的short和char一起进行补齐,补齐后的sizeof(X)的值就是24

总结:

在写struct和class的时候,对数据类型要按照从大到小或者从小到大的顺序,进行声明。


第一个例子:

char* ss = "0123456789"; sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针 注:这里ss是指针,32位机中占4byte,64位机中占8byte 
sizeof(*ss) 结果 1 ===》*ss是第一个字符
 char ss[] = "0123456789"; sizeof(ss) 结果 11 ===》ss是数组,计算到\0位置,因此是10+1 注:这里是ss数组,不是指针,还要注意最末尾的'\0'。如果这样定义一个char数组char ss[10] = "0123456789";编译不通过,数组界限溢出。
sizeof(*ss) 结果 1 ===》*ss是第一个字符
 char ss[100] = "0123456789"; sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
 strlen(ss) 结果是10 ===》strlen是个函数,内部实现是用一个循环计算到\0之前为止 
注意 int ss[100] = "0123456789"; sizeof(ss) 结果 400 ===》ss表示在内存中的大小 100×4 strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''\0''结尾的 char q[]="abc"; char p[]="a\n"; sizeof(q),sizeof(p),strlen(q),strlen(p); 结果是 4 3 3 2

第二个例子:

class X { int i; int j; char k; }; X x; cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐

sizeof深入理解。

  • 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
  • 2.sizeof是算符,strlen是函数。
  • 3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。sizeof还可以用函数做参数,比如:
    short mmax(){return 1;} printf("%d\n", sizeof(mmax()));
    输出的结果是sizeof(short),即2。
  • 但是sizeof(mmax) 则编译报错
  • .sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式 这个明显不对,MAX未定义的话,怎么可能编译通过呢
  • 4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
  • 5.大部分编译程序 在编译的时候就把sizeof计算过了是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
    char str[20]="0123456789"; int a=strlen(str); //a=10;
     int b=sizeof(str); //而b=20;
  • 6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
  • 7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
  • 8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
  • 9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
    fun(char [8]) fun(char [])
    都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去
    fun(unsiged char *p1, int len) { unsigned char* buf = new unsigned char[len+1];  memcpy(buf, p1, len); } 有关内容见: C++ PRIMER?
  • 10.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。visual studio里的内存补齐是在项目属性-》C/C++-》代码生成-》结构成员对齐,一般是默认值,还可以设为1、2、4、8、16字节,分别表示为结构体(struct、class,不包括union,union分到的内存等于它占内存最大的那个成员所需内存)内存分配时的最小单位为1、2、4、8、16字节,但是如果设置的值比结构体中占内存最大的那个成员所需内存还大,则设置无效。默认值就是指以占内存最大的那个成员所需内存为最小单
原创粉丝点击