sizeof(union) 、sizeof(struct) 和内存对齐技术

àì夳堔傛蜴生んèń 2022-08-27 01:30 227阅读 0赞

公式 整体对齐系数 = min((max(int,short,char), 设置的机器默认对齐字节) = 2

一,union:C/C++关键字 共用体(联合)

  1. 共用体的声明和共用体变量定义与结构十分相似。形式为:

[html] view plain copy

  1. union 共用体名
  2. {   
  3. 数据类型 成员名;   
  4. 数据类型 成员名;   
  5. …   
  6. } 变量名;
  1. 共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量.在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中最大的变量长度的整数倍(特别注意数组)

例子一:

union foo{

  int i;

  char c;

  double k;

  };

sizeof(foo); //double最长占用8字节,所以union foo大小为8字节

例子二: 

[html] view plain copy

  1. union A
  2. {
  3. int a[5]; //20
  4. short b; //2
  5. double c; //8
  6. char p2; //1
  7. };
  8. struct B {
  9. int n; // 4字节
  10. A a; // 24字节
  11. char c[10]; // 10字节
  12. };
  1. sizeof(A) ; //24 而不是20 ???
  2. sizeof(B) ; //48 而不是???
  3. 对齐: 分配内存时,每个成员放在长度倍数位置,如果不够,补位对齐
  4. 补齐: 对整个结构变量的空间要求总长度一定是最长的成员的倍数,不够补齐不管是对齐还是补齐,最长的成员长度超过4时,以4计。
  5. A实际占用内存大小为 20字节,但是要跟 8个字节的变量double的整数倍,对齐所以为 24
  6. 由于A实际占用24字节,则可以想象B实际占用38字节,但A8字节对齐的,所以int nchar c\[10\]也需要8字节对齐,总共8+24+16=48 字节。

例子三:

[html] view plain copy

  1. union f   
  2. {   
  3. char s[10];   
  4. int i;   
  5. };
  1. sizeof(f); // 12
  2. 解释:在这个union中,foo的内存空间的长度为12,是int型的3倍,而并不是数组的长度10
  3. 若把int改为double,则foo的内存空间为16,是double型的两倍。

二,struct

  1. 具体说明见内存对齐例子

三,内存对齐

  1. 1)概念:“内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。
  2. 2)原因:
  3. 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。   
  4. 2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因是:为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
  5. 3)对齐规则
  6.   每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令\#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。   
  7. 规则:   
  8. 1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset0的地方,以后每个数据成员的对齐按照\#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。   
  9. 2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照\#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。   
  10. 3、结合12可推断:当\#pragma packn值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

pragma pack(1) 时候

  1. 1>数据成员对齐:

[html] view plain copy

  1. #pragma pack(1)
  2. struct test_t
  3. {
  4. int a; /* int型, 长度4 > 1 按1对齐;起始offset=0 0%1=0;存放位置区间[0,3] */
  5. char b; /* char型, 长度1 = 1 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */
  6. short c; /* short型,长度2 > 1 按1对齐;起始offset=5 5%1=0;存放位置区间[5,6] */
  7. char d[6]; /* char型, 长度1 = 1 按1对齐;起始offset=7 7%1=0;存放位置区间[7,C] */
  8. };/*char d[6]要看成6个char型变量*/
  1. sizeof(test\_t) ; //输出为13
  2. 2>整体对齐

   整体对齐系数 = min((max(int,short,char), 1) = 1

   整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 13 /*13%1=0*/

pragma pack(2) 时候

  1. 1>成员数据对齐

  

[html] view plain copy

  1. #pragma pack(2)
  2. struct test_t {
  3. int a; /* int型,长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */
  4. char b; /* char型,长度1 < 2 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */
  5.   short c; /* short型,长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */
  6. char d[6]; /* char型,长度1 < 2 按1对齐;起始offset=8 8%1=0;存放位置区间[8,D] */
  7. };

  成员总大小=14

  2> 整体对齐

  整体对齐系数 = min((max(int,short,char), 2) = 2

  整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 14 /* 14%2=0 */

共用体

union u

{

 double a;

 int b;

};

union u2

{

 char a[13];

 int b;

};

union u3

{

 char a[13];

 char b;

};

cout<<sizeof(u)<<endl; // 8

cout<<sizeof(u2)<<endl; // 16

cout<<sizeof(u3)<<endl; // 13

  都知道union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于u来说,大小就是最大的double类型成员a了,所以sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间都是char[13]类型的数组,为什么u3的大小是13,而u2是16呢?关键在于u2中的成员int b。由于int类型成员的存在,使u2的对齐方式变成4,也就是说,u2的大小必须在4的对界上,所以占用的空间变成了16(最接近13的对界)。

  结论:复合数据类型,如union,struct,class的对齐方式为成员中对齐方式最大的成员的对齐方式。

这里有个陷阱,对于结构体中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子:

struct s1

{

 char a[8];

};

struct s2

{

 double d;

};

struct s3

{

 s1 s;

 char a;

};

struct s4

{

 s2 s;

 char a;

};

cout<<sizeof(s1)<<endl; // 8

cout<<sizeof(s2)<<endl; // 8

cout<<sizeof(s3)<<endl; // 9

cout<<sizeof(s4)<<endl; // 16;

  s1和s2大小虽然都是8,但是s1的对齐方式是1,s2是8(double),所以在s3和s4中才有这样的差异。

  所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。

发表评论

表情:
评论列表 (有 0 条评论,227人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++内存 内存对齐

    1 引言 操作系统的内存分配问题与内存对齐问题对于低层程序设计来说是非常重要的,对内存分配的理解直接影响到代码质量、正确率、效率以及程序员对内存使用情况、溢出、泄露等的判断力

    相关 C++内存对齐

    内存对齐 在我们的程序中,数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度。 我们还

    相关 内存对齐

    每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令\pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你