C++中的字节对齐
本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!
字节对齐
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 : 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;
}
执行结果例如以下:
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---|
这样改变默认的字节对齐方式能够更充分地利用存储空间,可是这会减少计算机读写数据的速度,是一种以时间换取空间的方式。
验证代码例如以下:
#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;
}
执行结果例如以下:
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
说明:静态变量存放在全局数据区内,而sizeof计算栈中分配的空间的大小,故不计算在内。
若加上#pragma pack(2)命令,则执行结果例如以下:
A1 size = 4
A2 size = 6
A3 size = 6
A4 size = 10
A5 size = 18
最新文章
- C#静态常量和动态常量的区别
- AraxisMerge和beyond Compare做git mergetool配置
- Netfilter/iptables的匹配方式及处理方法
- HTML之文本框关键字显示
- C#中如何操作2个list
- selenium页面元素操作(简易版)
- 2018.11.26 QLU新生赛部分题解
- SpringMVC处理器映射器和方法名称解析器
- 11、TopN实战
- 生产环境CPU过高问题定位
- NODE_ENV=production关于不同系统的写法
- 十五、Facade 窗口设计模式
- 微信小程序 canvas 绘图问题总结
- python网络编程之C/S架构介绍
- 关于TcpClient,Socket连接超时的几种处理方法
- 第134天:移动web开发的一些总结(二)
- UML动态模型(顺序图、协作图、状态图)
- 子查询语句的thinkphp实现
- [Elasticsearch] 多字段搜索 (二) - 最佳字段查询及其调优
- 用fontcreator创建了一个半成品的字体