现在的位置: 首页 > 综合 > 正文

C++中的字节对齐

2018年07月09日 ⁄ 综合 ⁄ 共 9431字 ⁄ 字号 评论关闭

字节对齐

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|----|

验证代码如下:

view plaincopy to clipboardprint?
#include <stdio.h>  
 
typedef struct 
{  
    char name[5];  
    int num;  
    short score;  
}student1;  
 
typedef struct 
{  
    int num;  
    char name[5];  
    short score;  
}student2;  
 
typedef struct 
{  
    int num;  
    short score;  
    char name[5];  
}student3;  
 
int main()  
{  
    student1 s1={"Tom",1001,90};  
    student2 s2={1002,"Mike",91};  
    student3 s3={1003,92,"Jack"};  
 
    printf("student1 size = %d/n",sizeof(s1));  
    printf("student2 size = %d/n",sizeof(s2));  
    printf("student3 size = %d/n",sizeof(s3));  
 
    printf("/nstudent1 address : 0x%08x/n",&s1);  
    printf("   name  address : 0x%08x/n",s1.name);  
    printf("   num   address : 0x%08x/n",&s1.num);  
    printf("   score address : 0x%08x/n",&s1.score);  
 
    printf("/nstudent2 address : 0x%08x/n",&s2);  
    printf("   num   address : 0x%08x/n",&s2.num);  
    printf("   name  address : 0x%08x/n",s2.name);  
    printf("   score address : 0x%08x/n",&s2.score);  
 
    printf("/nstudent3 address : 0x%08x/n",&s3);  
    printf("   num   address : 0x%08x/n",&s3.num);  
    printf("   score address : 0x%08x/n",&s3.score);  
    printf("   name  address : 0x%08x/n",s3.name);  
 
    return 0;  

#include <stdio.h>

typedef struct
{
 char name[5];
 int num;
 short score;
}student1;

typedef struct
{
 int num;
 char name[5];
 short score;
}student2;

typedef struct
{
 int num;
 short score;
 char name[5];
}student3;

int main()
{
 student1 s1={"Tom",1001,90};
 student2 s2={1002,"Mike",91};
 student3 s3={1003,92,"Jack"};

 printf("student1 size = %d/n",sizeof(s1));
 printf("student2 size = %d/n",sizeof(s2));
 printf("student3 size = %d/n",sizeof(s3));

 printf("/nstudent1 address : 0x%08x/n",&s1);
 printf("   name  address : 0x%08x/n",s1.name);
 printf("   num   address : 0x%08x/n",&s1.num);
 printf("   score address : 0x%08x/n",&s1.score);

 printf("/nstudent2 address : 0x%08x/n",&s2);
 printf("   num   address : 0x%08x/n",&s2.num);
 printf("   name  address : 0x%08x/n",s2.name);
 printf("   score address : 0x%08x/n",&s2.score);

 printf("/nstudent3 address : 0x%08x/n",&s3);
 printf("   num   address : 0x%08x/n",&s3.num);
 printf("   score address : 0x%08x/n",&s3.score);
 printf("   name  address : 0x%08x/n",s3.name);

 return 0;
}

运行结果如下:

view plaincopy to clipboardprint?
student1 size = 16  
student2 size = 12  
student3 size = 12  
 
student1 address : 0x0013ff70  
   name  address : 0x0013ff70  
   num   address : 0x0013ff78  
   score address : 0x0013ff7c  
 
student2 address : 0x0013ff64  
   num   address : 0x0013ff64  
   name  address : 0x0013ff68  
   score address : 0x0013ff6e  
 
student3 address : 0x0013ff58  
   num   address : 0x0013ff58  
   score address : 0x0013ff5c  
   name  address : 0x0013ff5e 
student1 size = 16
student2 size = 12
student3 size = 12

student1 address : 0x0013ff70
   name  address : 0x0013ff70
   num   address : 0x0013ff78
   score address : 0x0013ff7c

student2 address : 0x0013ff64
   num   address : 0x0013ff64
   name  address : 0x0013ff68
   score address : 0x0013ff6e

student3 address : 0x0013ff58
   num   address : 0x0013ff58
   score address : 0x0013ff5c
   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---|

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

验证代码如下:

view plaincopy to clipboardprint?
#include <stdio.h> 
 
#pragma pack(2)  
typedef struct 
{  
    char name[5];  
    int num;  
    short score;  
}student1;  
 
typedef struct 
{  
    int num;  
    char name[5];  
    short score;  
}student2;  
 
typedef struct 
{  
    int num;  
    short score;  
    char name[5];  
}student3; 
#pragma pack()  
 
int main()  
{  
    student1 s1={"Tom",1001,90};  
    student2 s2={1002,"Mike",91};  
    student3 s3={1003,92,"Jack"};  
 
    printf("student1 size = %d/n",sizeof(s1));  
    printf("student2 size = %d/n",sizeof(s2));  
    printf("student3 size = %d/n",sizeof(s3));  
 
    printf("/nstudent1 address : 0x%08x/n",&s1);  
    printf("   name  address : 0x%08x/n",s1.name);  
    printf("   num   address : 0x%08x/n",&s1.num);  
    printf("   score address : 0x%08x/n",&s1.score);  
 
    printf("/nstudent2 address : 0x%08x/n",&s2);  
    printf("   num   address : 0x%08x/n",&s2.num);  
    printf("   name  address : 0x%08x/n",s2.name);  
    printf("   score address : 0x%08x/n",&s2.score);  
 
    printf("/nstudent3 address : 0x%08x/n",&s3);  
    printf("   num   address : 0x%08x/n",&s3.num);  
    printf("   score address : 0x%08x/n",&s3.score);  
    printf("   name  address : 0x%08x/n",s3.name);  
 
    return 0;  

#include <stdio.h>

#pragma pack(2)
typedef struct
{
 char name[5];
 int num;
 short score;
}student1;

typedef struct
{
 int num;
 char name[5];
 short score;
}student2;

typedef struct
{
 int num;
 short score;
 char name[5];
}student3;
#pragma pack()

int main()
{
 student1 s1={"Tom",1001,90};
 student2 s2={1002,"Mike",91};
 student3 s3={1003,92,"Jack"};

 printf("student1 size = %d/n",sizeof(s1));
 printf("student2 size = %d/n",sizeof(s2));
 printf("student3 size = %d/n",sizeof(s3));

 printf("/nstudent1 address : 0x%08x/n",&s1);
 printf("   name  address : 0x%08x/n",s1.name);
 printf("   num   address : 0x%08x/n",&s1.num);
 printf("   score address : 0x%08x/n",&s1.score);

 printf("/nstudent2 address : 0x%08x/n",&s2);
 printf("   num   address : 0x%08x/n",&s2.num);
 printf("   name  address : 0x%08x/n",s2.name);
 printf("   score address : 0x%08x/n",&s2.score);

 printf("/nstudent3 address : 0x%08x/n",&s3);
 printf("   num   address : 0x%08x/n",&s3.num);
 printf("   score address : 0x%08x/n",&s3.score);
 printf("   name  address : 0x%08x/n",s3.name);

 return 0;
}

运行结果如下:

view plaincopy to clipboardprint?
student1 size = 12  
student2 size = 12  
student3 size = 12  
 
student1 address : 0x0013ff74  
   name  address : 0x0013ff74  
   num   address : 0x0013ff7a  
   score address : 0x0013ff7e  
 
student2 address : 0x0013ff68  
   num   address : 0x0013ff68  
   name  address : 0x0013ff6c  
   score address : 0x0013ff72  
 
student3 address : 0x0013ff5c  
   num   address : 0x0013ff5c  
   score address : 0x0013ff60  
   name  address : 0x0013ff62 
student1 size = 12
student2 size = 12
student3 size = 12

student1 address : 0x0013ff74
   name  address : 0x0013ff74
   num   address : 0x0013ff7a
   score address : 0x0013ff7e

student2 address : 0x0013ff68
   num   address : 0x0013ff68
   name  address : 0x0013ff6c
   score address : 0x0013ff72

student3 address : 0x0013ff5c
   num   address : 0x0013ff5c
   score address : 0x0013ff60
   name  address : 0x0013ff62

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

view plaincopy to clipboardprint?
student1 size = 11  
student2 size = 11  
student3 size = 11  
 
student1 address : 0x0013ff74  
   name  address : 0x0013ff74  
   num   address : 0x0013ff79  
   score address : 0x0013ff7d  
 
student2 address : 0x0013ff68  
   num   address : 0x0013ff68  
   name  address : 0x0013ff6c  
   score address : 0x0013ff71  
 
student3 address : 0x0013ff5c  
   num   address : 0x0013ff5c  
   score address : 0x0013ff60  
   name  address : 0x0013ff62 
student1 size = 11
student2 size = 11
student3 size = 11

student1 address : 0x0013ff74
   name  address : 0x0013ff74
   num   address : 0x0013ff79
   score address : 0x0013ff7d

student2 address : 0x0013ff68
   num   address : 0x0013ff68
   name  address : 0x0013ff6c
   score address : 0x0013ff71

student3 address : 0x0013ff5c
   num   address : 0x0013ff5c
   score address : 0x0013ff60
   name  address : 0x0013ff62

4. 例子

程序如下:

view plaincopy to clipboardprint?
#include <stdio.h>  
 
class A1  
{  
public:  
    int a;  
    static int b;  
 
    A1();  
    ~A1();  
};  
 
class A2  
{  
public:  
    int a;  
    char c;  
 
    A2();  
    ~A2();  
};  
 
class A3  
{  
public:  
    float a;  
    char c;  
 
    A3();  
    ~A3();  
};  
 
class A4  
{  
public:  
    float a;  
    int b;  
    char c;  
      
    A4();  
    ~A4();  
};  
 
class A5  
{  
public:  
    double d;  
    float a;  
    int b;  
    char c;  
      
    A5();  
    ~A5();  
};  
 
main()  
{  
    printf("A1 size = %d/n",sizeof(A1));  
    printf("A2 size = %d/n",sizeof(A2));  
    printf("A3 size = %d/n",sizeof(A3));  
    printf("A4 size = %d/n",sizeof(A4));  
    printf("A5 size = %d/n",sizeof(A5));  

#include <stdio.h>

class A1
{
public:
 int a;
 static int b;

 A1();
 ~A1();
};

class A2
{
public:
 int a;
 char c;

 A2();
 ~A2();
};

class A3
{
public:
 float a;
 char c;

 A3();
 ~A3();
};

class A4
{
public:
 float a;
 int b;
 char c;
 
 A4();
 ~A4();
};

class A5
{
public:
 double d;
 float a;
 int b;
 char c;
 
 A5();
 ~A5();
};

main()
{
 printf("A1 size = %d/n",sizeof(A1));
 printf("A2 size = %d/n",sizeof(A2));
 printf("A3 size = %d/n",sizeof(A3));
 printf("A4 size = %d/n",sizeof(A4));
 printf("A5 size = %d/n",sizeof(A5));
}

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

view plaincopy to clipboardprint?
A1 size = 4  
A2 size = 8  
A3 size = 8  
A4 size = 12  
A5 size = 24 
A1 size = 4
A2 size = 8
A3 size = 8
A4 size = 12
A5 size = 24

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

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

view plaincopy to clipboardprint?
A1 size = 4  
A2 size = 6  
A3 size = 6  
A4 size = 10  
A5 size = 18 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/livelylittlefish/archive/2009/01/29/3854725.aspx

抱歉!评论已关闭.