1、概念
字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。
2、理由
需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误。
3、理解
字节对齐的几大原则:
- 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
- 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储。)
- 联合体作为成员:按照其包含的长度最大的数据类型对齐。
- 收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍。不足的要补齐。
由于在x86下,GCC默认按4字节对齐,比如:
struct stu{
char sex;
int length;
char name[10];
};
struct stu my_stu;
它会在 sex 后面填充三个字节,使其与 int 长度对齐,name 后面填充两个字节使整个结构体对齐,使得 sizeof(my_stu) 为 20(4 的倍数),而不是15。
4、例子
#include <iostream>
using namespace std;
//#pragma pack(1)
typedef struct bb
{
int id; //[0]....[3]
double weight; //[8].....[15] 原则1
float height; //[16]..[19],总长要为8的整数倍,补齐[20]...[23] 原则3
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
int id; //[4]...[7] 原则1
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47] 原则2
}AA;
int main()
{
AA a;
cout << sizeof(a) << " " << sizeof(BB) << endl;
system("pause");
return 0;
}
结果是:48 24
对于 BB:4+[4]+8+4+[4]=24,其中 [] 表示补齐的字节数。
对于 a :2+[2]+4+8+2+[6]+24=48,同样地,[] 表示补齐的字节数。
5、#pragma pack()
再讲讲#pragma pack()。在上述代码前加一句 #pragma pack(1),则输出的结果就变得很不一样:32 16
对于 BB:4+8+4=16
对于 a:2+4+8+2+16=32
所有的补齐字节都消失了,这就相当于没有内存对齐的情况。#pragma pack(1) 就是告诉编译器:所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则。
在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
- 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
- 使用伪指令#pragma pack (),取消自定义字节对齐方式。
6、__attribute__选项
我们可以按照自己设定的对齐大小来编译程序,GNU使用__attribute__选项来设置,比如我们想让刚才的结构按一字节对齐,我们可以这样定义结构体:
struct stu{
char sex;
int length;
char name[10];
}__attribute__ ((aligned (1)));
struct stu my_stu;
则sizeof(my_stu)可以得到大小为15。上面的定义等同于:
struct stu{
char sex;
int length;
char name[10];
}__attribute__ ((packed));
struct stu my_stu;
__attribute__((packed))得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。
参考链接:
1、http://blog.csdn.net/21aspnet/article/details/6729724/
2、http://blog.csdn.net/hairetz/article/details/4084088