[转]结构体字节对齐规则

  1 //先介绍三个概念:自身对齐值、指定对齐值、有效对齐值。
  2 
  3 //自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;
  4 //指定对齐值:编译器或程序员指定的对齐值,32位单片机的指定对齐值默认是4;
  5 //有效对齐值:自身对齐值和指定对齐值中较小的那个。
  6 
  7 //对齐有两个规则:
  8 
  9 //1、不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。
 10 // 结构体的有效对齐值是   [其最大数据成员的自身对齐值] 和 [编译器或程序员指定的对齐值] 中较小的那个;
 11 //2、存放成员的起始地址必须是该成员有效对齐值的整数倍。
 12 
 13 // 64 位系统 指定对齐值默认是8;
 14 // 编译器或程序员指定的对齐值,通过下面的命令,指定为 4 byte对齐
 15 #pragma pack (4)
 16 
 17 // 简单类型的结构体对齐
 18 typedef struct {
 19     char a;         // 1  byte  3 byte reserved(成员b起始对齐)
 20     float b;        // 4  byte
 21     char c;         // 1  byte  3 byte reserved(结构体本身对齐)
 22 }StructA;           // 12 byte
 23 
 24 typedef struct {
 25     char a;         // 1  byte  3 byte reserved(成员b起始对齐)
 26     double b;       // 8  byte
 27     char c;         // 1  byte  3 byte reserved(结构体本身对齐)
 28 }StructAA;          // 16
 29 
 30 typedef struct {
 31     double a;       // 8  byte
 32     char b;         // 1  byte
 33     char c;         // 1  byte  2 byte reserved(结构体本身对齐)
 34 }StructAAA;         // 12
 35 
 36 typedef struct {
 37     char a;         // 1  byte
 38     char b;         // 1  byte
 39     char c;         // 1  byte
 40 }StructAAAA;        // 3
 41 
 42 typedef struct {
 43     short a;         // 2  byte
 44     char b;          // 1  byte  1 byte reserved(结构体本身对齐)
 45 }StructAAAAA;        // 4
 46 
 47 // 带有数组的结构体对齐
 48 // 数组本编译器理解为多个基本类型的连续,并没有把他当做一个整体进行对齐
 49 typedef struct {
 50     char a;         // 1  byte  3 byte reserved(成员b起始对齐)
 51     float b[3];     // 12 byte
 52     char c;         // 1  byte  3 byte reserved(结构体本身对齐)
 53 }StructB;           // 20 byte
 54 
 55 typedef struct {
 56     char a;         // 1  byte
 57     char b[3];      // 3  byte
 58     char c;         // 1  byte
 59 }StructBB;          // 5  byte 
 60 
 61 typedef struct {
 62     char a;         // 1  byte  1 byte reserved(成员b起始对齐)
 63     short b[3];     // 6  byte
 64     char c;         // 1  byte  1 byte reserved (结构体本身对齐)
 65 }StructBBB;         // 10 byte 
 66 
 67 // 结构体嵌套对齐对齐
 68 // 嵌套的结构体是按结构体整体(可以认为是新的数据类型)进行对齐,
 69 // 结构体变量的自身对齐值是  [其最大数据成员的自身对齐值] 和 [编译器或程序员指定的对齐值] 中较小的那个;
 70 
 71 typedef struct {
 72     char a[3];      // 3  byte
 73 }StructC1;          // 3  byte 
 74 
 75 typedef struct {
 76     short a[3];     // 6  byte
 77 }StructC2;          // 6  byte 
 78 
 79 typedef struct {
 80     double a;     // 8   byte
 81     char b;       // 1   byte  3 byte reserved (结构体本身对齐) 
 82 }StructC3;        // 12  byte 
 83 
 84 typedef struct {
 85     short a;      // 2   byte
 86     char b;       // 1   byte  1 byte reserved (结构体本身对齐) 
 87 }StructC4;        // 4  byte 
 88 
 89 typedef struct {
 90     char a;         // 1  byte  3 byte reserved(成员b起始对齐)
 91     StructA b;      // 12 byte  [大小是12,指定对齐值4,以指定对齐为有效对齐]
 92     char c;         // 1  byte  3 byte reserved(结构体本身对齐)
 93 }StructD;           // 20 byte 
 94 
 95 typedef struct {
 96     char a;         // 1  byte 
 97     StructC1 b;     // 3  byte   
 98     char c;         // 1  byte 
 99 }StructDD;          // 5  byte 
100 
101 typedef struct {
102     char a;         // 1  byte  1 byte reserved(成员b起始对齐) 
103     StructC2 b;     // 6  byte   
104     char c;         // 1  byte  1 byte reserved(成员b起始对齐)  
105 }StructDDD;         // 10 byte 
106 //--------特殊的例子----------//
107 typedef struct {
108     StructC3 a;     // 12  byte   
109     char b;         // 1   byte  3 byte reserved(成员b起始对齐)  
110 }StructDDDD;        // 16  byte 
111 //--------特殊的例子----------//
112 typedef struct {
113     char a;         // 1  byte   1 byte reserved(成员b起始对齐)   
114     StructC4 b;     // 4  byte   
115     char c;         // 1   byte  1 byte reserved(成员b起始对齐)  
116 }StructDDDDD;       // 6  byte 

 

先介绍三个概念:自身对齐值、指定对齐值、有效对齐值。

 

自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;

 

指定对齐值:编译器或程序员指定的对齐值,32位单片机的指定对齐值默认是4;

 

有效对齐值:自身对齐值和指定对齐值中较小的那个。

 

对齐有两个规则:

1、不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。结构体的有效对齐值是其最大数据成员的自身对齐值

 

2、存放成员的起始地址必须是该成员有效对齐值的整数倍

 

举四个例子

 

假如结构体起始地址是0x0000,

成员a的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0000是1的整数倍,故a存放起始地址是0x0000,占一个字节;

成员b的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0001是1的整数倍,故b存放起始地址是0x0001,占一个字节;

成员c的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0002是1的整数倍,故c存放起始地址是0x0002,占一个字节;

成员d的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0003是1的整数倍,故d存放起始地址是0x0003,占一个字节;

 

此时结构体A的有效对齐值是其最大数据成员的自身对齐值,它的成员都是char类型,故结构体A的有效对齐值是1.

结构体A的存储结构如下,其中Y是根据规则1补齐的字节,x是规则2补齐的字节。

 

0x0000

0x00001

0x0002

0x0003

a

b

c

d

 

根据以上规则可以知道其他结构体的存储结构:

结构体B占6个字节

0x0000

0x00001

0x0002

0x0003

0x0004

0x0005

a

x

b

b

c

d

 

结构体C占12个字节

成员a的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0000是1的整数倍,故a存放起始地址是0x0000,占一个字节;

成员b的自身对齐值4,指定对齐值4,所以有效对齐值是4,地址0x0004是4的整数倍,故b存放起始地址是0x0004,占四个字节;

成员c的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0008是1的整数倍,故c存放起始地址是0x0008,占一个字节;

成员d的自身对齐值1,指定对齐值4,所以有效对齐值是1,地址0x0009是1的整数倍,故d存放起始地址是0x0009,占一个字节;

结构体C的成员占据10个字节,而结构体C的有效对齐值是其成员b的自身对齐值4,10不是4的倍数,故还需补齐两个字节,此时结构体C占据12个字节,是4的倍数

如下:

0x0000

0x00001

0x0002

0x0003

0x0004

0x0005

0x0006

0x0007

0x0008

0x0009

0x000A

0x000B

a

x

x

x

b

b

b

b

c

d

Y

Y

 

结构体D占16个字节

0x0000

0x00001

0x0002

0x0003

0x0004

0x0005

0x0006

0x0007

0x0008

0x0009

0x000A

0x000B

0x000C

0x000D

0x000E

0x000F

a

x

x

x

b

b

b

b

b

b

b

b

c

d

Y

Y

代码验证如下:

 

 

 

posted @ 2019-10-17 11:12  博客园—哆啦A梦  阅读(931)  评论(0)    收藏  举报