C++中的字节对齐

字节对齐

 

1. 基本概念
字节对齐:计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如:整型(int)数据占4个字节,字符型(char)数据占一个字节,短整型(short)数据占两个字节,等等。计算机为了快速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)可以存放在任何地址位置(被1整除),短整型(short)数据存储在地址能被2整除的起始位置。这就是默认字节对齐方式。

 

2. 举例说明
很显然默认对齐方式会浪费很多空间,例如如下结构:
struct student
{
    char name[5];
    int num;
    short score;
}
本来只用了11bytes(5+4+2)的空间,但是由于int型默认4字节对齐,存放在地址能被4整除的起始位置,即:如果name[5]从0开始存放,它占5bytes,而num则从第8(偏移量)个字节开始存放。所以sizeof(student)=16。于是中间空出几个字节闲置着。但这样便于计算机快速读写数据,是一种以空间换取时间的方式。其数据对齐如下图:

|char|char|char|char|
|char|----|----|----|
|--------int--------|
|--short--|----|----|

 

如果我们将结构体中变量的顺序改变为:
struct student
{
    int num;
    char name[5];
    short score;
}
则,num从0开始存放,而name从第4(偏移量)个字节开始存放,连续5个字节,score从第10(偏移量)开始存放,故sizeof(student)=12。其数据对齐如下图: 

|--------int--------|
|char|char|char|char|
|char|----|--short--| 

 

如果我们将结构体中变量的顺序再次改为为:
struct student
{
    int num;
    short score;
    char name[5];
}
则,sizeof(student)=12。其数据对齐如下图: 

|--------int--------|
|--short--|char|char|
|char|char|char|----| 

 

验证代码如下:

[c-sharp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. typedef struct  
  4. {  
  5.     char name[5];  
  6.     int num;  
  7.     short score;  
  8. }student1;  
  9.   
  10. typedef struct  
  11. {  
  12.     int num;  
  13.     char name[5];  
  14.     short score;  
  15. }student2;  
  16.   
  17. typedef struct  
  18. {  
  19.     int num;  
  20.     short score;  
  21.     char name[5];  
  22. }student3;  
  23.   
  24. int main()  
  25. {  
  26.     student1 s1={"Tom",1001,90};  
  27.     student2 s2={1002,"Mike",91};  
  28.     student3 s3={1003,92,"Jack"};  
  29.   
  30.     printf("student1 size = %d/n",sizeof(s1));  
  31.     printf("student2 size = %d/n",sizeof(s2));  
  32.     printf("student3 size = %d/n",sizeof(s3));  
  33.   
  34.     printf("/nstudent1 address : 0x%08x/n",&s1);  
  35.     printf("   name  address : 0x%08x/n",s1.name);  
  36.     printf("   num   address : 0x%08x/n",&s1.num);  
  37.     printf("   score address : 0x%08x/n",&s1.score);  
  38.   
  39.     printf("/nstudent2 address : 0x%08x/n",&s2);  
  40.     printf("   num   address : 0x%08x/n",&s2.num);  
  41.     printf("   name  address : 0x%08x/n",s2.name);  
  42.     printf("   score address : 0x%08x/n",&s2.score);  
  43.   
  44.     printf("/nstudent3 address : 0x%08x/n",&s3);  
  45.     printf("   num   address : 0x%08x/n",&s3.num);  
  46.     printf("   score address : 0x%08x/n",&s3.score);  
  47.     printf("   name  address : 0x%08x/n",s3.name);  
  48.   
  49.     return 0;  
  50. }  

 

运行结果如下:

[c-sharp]  view plain copy
  1. student1 size = 16  
  2. student2 size = 12  
  3. student3 size = 12  
  4.   
  5. student1 address : 0x0013ff70  
  6.    name  address : 0x0013ff70  
  7.    num   address : 0x0013ff78  
  8.    score address : 0x0013ff7c  
  9.   
  10. student2 address : 0x0013ff64  
  11.    num   address : 0x0013ff64  
  12.    name  address : 0x0013ff68  
  13.    score address : 0x0013ff6e  
  14.   
  15. student3 address : 0x0013ff58  
  16.    num   address : 0x0013ff58  
  17.    score address : 0x0013ff5c  
  18.    name  address : 0x0013ff5e  

 

3. #pragma pack()命令
为了节省空间,我们可以在编码时通过#pragma pack()命令指定程序的对齐方式,括号中是对齐的字节数,若该命令括号中的内容为空,则为默认对齐方式。例如,对于上面第一个结构体,如果通过该命令手动设置对齐字节数如下:

 

#pragma pack(2) //设置2字节对齐
struct strdent
{
    char name[5]; //本身1字节对齐,比2字节对齐小,按1字节对齐
    int num;          //本身4字节对齐,比2字节对齐大,按2字节对齐
    short score;    //本身也2字节对齐,仍然按2字节对齐
}
#pragma pack() //取消设置的字节对齐方式

 

则,num从第6(偏移量)个字节开始存放,score从第10(偏移量)个字节开始存放,故sizeof(student)=12,其数据对齐如下图:
|char|char|
|char|char|
|char|-----|
|----int----|
|----int----|
|--short---|

 

这样改变默认的字节对齐方式可以更充分地利用存储空间,但是这会降低计算机读写数据的速度,是一种以时间换取空间的方式。

 

验证代码如下:

[c-sharp]  view plain copy
  1. #include <stdio.h>  
  2.  
  3. #pragma pack(2)  
  4. typedef struct  
  5. {  
  6.     char name[5];  
  7.     int num;  
  8.     short score;  
  9. }student1;  
  10.   
  11. typedef struct  
  12. {  
  13.     int num;  
  14.     char name[5];  
  15.     short score;  
  16. }student2;  
  17.   
  18. typedef struct  
  19. {  
  20.     int num;  
  21.     short score;  
  22.     char name[5];  
  23. }student3;  
  24. #pragma pack()  
  25.   
  26. int main()  
  27. {  
  28.     student1 s1={"Tom",1001,90};  
  29.     student2 s2={1002,"Mike",91};  
  30.     student3 s3={1003,92,"Jack"};  
  31.   
  32.     printf("student1 size = %d/n",sizeof(s1));  
  33.     printf("student2 size = %d/n",sizeof(s2));  
  34.     printf("student3 size = %d/n",sizeof(s3));  
  35.   
  36.     printf("/nstudent1 address : 0x%08x/n",&s1);  
  37.     printf("   name  address : 0x%08x/n",s1.name);  
  38.     printf("   num   address : 0x%08x/n",&s1.num);  
  39.     printf("   score address : 0x%08x/n",&s1.score);  
  40.   
  41.     printf("/nstudent2 address : 0x%08x/n",&s2);  
  42.     printf("   num   address : 0x%08x/n",&s2.num);  
  43.     printf("   name  address : 0x%08x/n",s2.name);  
  44.     printf("   score address : 0x%08x/n",&s2.score);  
  45.   
  46.     printf("/nstudent3 address : 0x%08x/n",&s3);  
  47.     printf("   num   address : 0x%08x/n",&s3.num);  
  48.     printf("   score address : 0x%08x/n",&s3.score);  
  49.     printf("   name  address : 0x%08x/n",s3.name);  
  50.   
  51.     return 0;  
  52. }  

 

运行结果如下:

[c-sharp]  view plain copy
  1. student1 size = 12  
  2. student2 size = 12  
  3. student3 size = 12  
  4.   
  5. student1 address : 0x0013ff74  
  6.    name  address : 0x0013ff74  
  7.    num   address : 0x0013ff7a  
  8.    score address : 0x0013ff7e  
  9.   
  10. student2 address : 0x0013ff68  
  11.    num   address : 0x0013ff68  
  12.    name  address : 0x0013ff6c  
  13.    score address : 0x0013ff72  
  14.   
  15. student3 address : 0x0013ff5c  
  16.    num   address : 0x0013ff5c  
  17.    score address : 0x0013ff60  
  18.    name  address : 0x0013ff62  

 

若该为#pragma pack(1),则运行结果如下:

[c-sharp]  view plain copy
  1. student1 size = 11  
  2. student2 size = 11  
  3. student3 size = 11  
  4.   
  5. student1 address : 0x0013ff74  
  6.    name  address : 0x0013ff74  
  7.    num   address : 0x0013ff79  
  8.    score address : 0x0013ff7d  
  9.   
  10. student2 address : 0x0013ff68  
  11.    num   address : 0x0013ff68  
  12.    name  address : 0x0013ff6c  
  13.    score address : 0x0013ff71  
  14.   
  15. student3 address : 0x0013ff5c  
  16.    num   address : 0x0013ff5c  
  17.    score address : 0x0013ff60  
  18.    name  address : 0x0013ff62  

 

4. 例子

 

程序如下:

[c-sharp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. class A1  
  4. {  
  5. public:  
  6.     int a;  
  7.     static int b;  
  8.   
  9.     A1();  
  10.     ~A1();  
  11. };  
  12.   
  13. class A2  
  14. {  
  15. public:  
  16.     int a;  
  17.     char c;  
  18.   
  19.     A2();  
  20.     ~A2();  
  21. };  
  22.   
  23. class A3  
  24. {  
  25. public:  
  26.     float a;  
  27.     char c;  
  28.   
  29.     A3();  
  30.     ~A3();  
  31. };  
  32.   
  33. class A4  
  34. {  
  35. public:  
  36.     float a;  
  37.     int b;  
  38.     char c;  
  39.       
  40.     A4();  
  41.     ~A4();  
  42. };  
  43.   
  44. class A5  
  45. {  
  46. public:  
  47.     double d;  
  48.     float a;  
  49.     int b;  
  50.     char c;  
  51.       
  52.     A5();  
  53.     ~A5();  
  54. };  
  55.   
  56. main()  
  57. {  
  58.     printf("A1 size = %d/n",sizeof(A1));  
  59.     printf("A2 size = %d/n",sizeof(A2));  
  60.     printf("A3 size = %d/n",sizeof(A3));  
  61.     printf("A4 size = %d/n",sizeof(A4));  
  62.     printf("A5 size = %d/n",sizeof(A5));  
  63. }  

 

该例子采取默认对齐方式,运行结果如下:

[c-sharp]  view plain copy
  1. A1 size = 4  
  2. A2 size = 8  
  3. A3 size = 8  
  4. A4 size = 12  
  5. A5 size = 24  

A5结构体大小按照字节对齐为8+4+4+4=20,还必须满足能被结构体中每个变量所占的大小整除。因为有double,所以为24字节。

说明:静态变量存放在全局数据区内,而sizeof计算栈中分配的空间的大小,故不计算在内。

若加上#pragma pack(2)命令,则运行结果如下:

[c-sharp]  view plain copy
  1. A1 size = 4  
  2. A2 size = 6  
  3. A3 size = 6  
  4. A4 size = 10  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值