您的位置:首页 > 编程语言 > C语言/C++

C++中的字节对齐机制

2013-03-22 22:43 197 查看
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|----|

验证代码如下:

#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 : 0xx\n",&s1);

printf(" name address : 0xx\n",s1.name);

printf(" num address : 0xx\n",&s1.num);

printf(" score address : 0xx\n",&s1.score);

printf("\nstudent2 address : 0xx\n",&s2);

printf(" num address : 0xx\n",&s2.num);

printf(" name address : 0xx\n",s2.name);

printf(" score address : 0xx\n",&s2.score);

printf("\nstudent3 address : 0xx\n",&s3);

printf(" num address : 0xx\n",&s3.num);

printf(" score address : 0xx\n",&s3.score);

printf(" name address : 0xx\n",s3.name);

return 0;

}

运行结果如下:

student1 size = 16

student2 size = 12

student3 size = 12

student1 address : 0x0012ff70

name address : 0x0012ff70

num address : 0x0012ff78

score address : 0x0012ff7c

student2 address : 0x0012ff64

num address : 0x0012ff64

name address : 0x0012ff68

score address : 0x0012ff6e

student3 address : 0x0012ff58

num address : 0x0012ff58

score address : 0x0012ff5c

name address : 0x0012ff5e

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

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

验证代码如下:

#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 : 0xx\n",&s1);

printf(" name address : 0xx\n",s1.name);

printf(" num address : 0xx\n",&s1.num);

printf(" score address : 0xx\n",&s1.score);

printf("\nstudent2 address : 0xx\n",&s2);

printf(" num address : 0xx\n",&s2.num);

printf(" name address : 0xx\n",s2.name);

printf(" score address : 0xx\n",&s2.score);

printf("\nstudent3 address : 0xx\n",&s3);

printf(" num address : 0xx\n",&s3.num);

printf(" score address : 0xx\n",&s3.score);

printf(" name address : 0xx\n",s3.name);

return 0;

}

运行结果如下:

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),则运行结果如下:

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. 例子

程序如下:

#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));

}

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

A1 size = 4

A2 size = 8

A3 size = 8

A4 size = 12

A5 size = 24
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: