详解4字节对齐

所谓的字节对齐,就是各种类型的数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这个就是对齐。我们经常听说的对齐在N上,它的含义就是数据的存放起始地址%N==0。具体对齐规则会在下面的篇幅中介绍。首先还是让我们来看一下,为什么要进行字节对齐吧。
 
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU,诸如SPARC在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构上必须编程必须保证字节对齐。而有些平台对于没有进行对齐的数据进行存取时会产生效率的下降。让我们来以x86为例看一下如果在不进行对齐的情况下,会带来什么样子的效率低下问题,看下面的数据结构声明:

view plaincopy to clipboardprint?
01.struct A {  
02.    char c;  
03.    int i;  
04.};  
05.struct A a;

Code 13-1
 
假设变量a存放在内存中的起始地址为0x00,那么其成员变量c的起始地址为0x00,成员变量i的起始地址为0x01,变量a一共占用了5个字节。当CPU要对成员变量c进行访问时,只需要一个读周期即可。而如若要对成员变量i进行访问,那么情况就变得有点复杂了,首先CPU用了一个读周期,从0x00处读取了4个字节(注意由于是32位架构),然后将0x01-0x03的3个字节暂存,接着又花费了一个读周期读取了从0x04-0x07的4字节数据,将0x04这个字节与刚刚暂存的3个字节进行拼接从而读取到成员变量i的值。为了读取这个成员变量i,CPU花费了整整2个读周期。试想一下,如果数据成员i的起始地址被放在了0x04处,那么读取其所花费的周期就变成了1,显然引入字节对齐可以避免读取效率的下降,但这同时也浪费了3个字节的空间(0x01-0x03)。
 
有了上述的基本概念之后,让我们来看一下,编译器是按照什么样的原则进行对齐的。首先有3个重要的概念:自身对齐值,指定对齐值和有效对齐值。
 
自身对齐值:即数据类型的自身的对齐值。例如char型的数据,其自身对齐值为1字节;short型的数据,其自身对齐值为2字节;int,float,long类型,其自身对齐值为4字节;double类型,其自身对齐值为4字节;而struct和class类型的数据其自身对齐值为其成员变量中自身对齐值最大的那个值。
 
指定对齐值:#pragma pack (value)时指定的对齐值value
 
有效对齐值:上述两个对齐值中最小的那个。
 
我们一般说的对齐在N上,都是指有效对齐在N上。说了这么多,还是让我们先来看一些例子来加深对这些概念的理解吧。例:假设在x86机器上,假设编译器按默认4字节进行对齐

view plaincopy to clipboardprint?
01.struct A {  
02.    char c;  
03.    int i;  
04.    short s;  
05.};  
06.  
07.#pragma pack (2)   /* 指定按2字节对齐 */  
08.struct B {  
09.    char c;  
10.    short s;  
11.    int i;  
12.};  
13.#pragma pack ()    /* 恢复默认对齐 */

Code 13-2
 
让我们来考虑一下sizeof(struct A)和sizeof(struct B)的结果各应该是什么。首先来看sizeof(struct A),假设A的起始地址为0x00,做这样的假设只是为了更方便理解,其实A始终被放在对齐边界上,这并不影响sizeof的结果,在接下来的例子中,我们也会继续沿用这个假设。言归正传,数据成员c的自身对齐值=1,指定对齐值=4(默认),所以其有效对齐值为1,因0x00%1==0,所以它被存放在0x00处;数据成员i的自身对齐值=4,指定对齐值=4,可得出其有效对齐值为4,因0x01%4 != 0,因此它应该被存放在0x04地址处,占用0x05,0x06,0x07共4个字节;接下来看数据成员s的自身对齐值=2,指定对齐值=4,得出有效对齐值为2,因0x08%2 == 0,因此它被存放在起始地址为0x08处,并占用2字节;最后再看数据结构A自身的对齐值=4(最大数据成员自身对齐值),指定对齐值=4,得有效对齐值为4,因0x0A%4 != 0,因此多占用0x0A和0x0B为结构体A所用(这一步的作用是基于结构体数组的出发,对于结构体或者类,要将它们补充成其有效对齐值的整数倍,这点请千万注意)。由此可见sizeof(struct A)的结果应该是=1+3(空闲空间)+4+2+2(结构体补充)=12字节。
 
接下来让我们考察sizeof(struct B)的结果。这里需要注意的是,在B被声明前,指定对齐值已经被设置为2个字节。数据成员c的有效对齐值为1,存放起址0x00,s的有效对齐值为2,存放起址0x02,i的有效对齐值也为2,存放起址为0x04,累加起来一共是8个字节,已经是数据结构B的有效对齐值2的整数倍了。因此sizeof(struct B)的结果8个字节。
 
看到这里,应该对字节对齐有了一定的了解了吧。接下来我们要看一个更加复杂的例子:假设在x86机器上,假设编译器按默认4字节进行对齐

view plaincopy to clipboardprint?
01.#pragma pack(8)  
02.struct S1 {  
03.    char a;  
04.    long b;  
05.};  
06.  
07.struct S2 {  
08.    char c;  
09.    struct S1 d;  
10.    long long e;  
11.};  
12.#pragma pack()  
13.

Code 13-3
 
运用上面所学到的知识,应该不难得出sizeof(struct S1)的值为8字节,其中a的有效对齐值为1,b的有效对齐值为4,结构S1的有效对齐值为4。现在让我们来看看sizeof(struct S2)的值会是多少呢?首先成员c的有效对齐值为1,S1的自身对齐值为成员的最大自身对齐值,即4字节,其指定对齐值为8,则其有效对齐值也为4,存放起址应该为0x04,并且占用8个字节(0x04+0x08=0x0C),其中0x01-0x03被用来填充。接下去数据成员e的有效对齐值为4,存放起址应该是0x0D % 8 == 0,占用8个字节(0x10)。最后考察S2本身的有效对齐值应该是4字节,而0x0D%8==0,就不需要填充了,因此sizeof(struct S2)=20。
 
在vc6工具中,我们可以选择[project]->[Settings]->[C/C++]->[Code Generation]->[Struct member alignment]来更改默认对齐字节数。
 
参考:http://www.sco.com/developers/devspecs/abi386-4.pdf

时间: 2024-11-03 05:34:14

详解4字节对齐的相关文章

c++内存中字节对齐问题详解[转载]

一.什么是字节对齐,为什么要对齐?     现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐.     对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在

C语言:内存字节对齐详解[转载]

一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐

c++内存中字节对齐问题详解

一.介绍 什么是字节对齐 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 字节对齐的原因和作用 各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字

struct/class等内存字节对齐问题详解

问题引入 定义一个结构体的一般形式为: struct 结构体名 { //类型说明符 成员名; }; 例如有如下结构体: struct Stu { int id; char sex; float hight; }; 那么一个这样的结构体变量占多大内存呢?也就是 cout<<sizeof(Stu)<<endl; 会输出什么? 在了解字节对齐方式之前想当然的会以为:sizeof(Stu) = sizeof(int)+sizeof(char)+sizeof(float) = 9. 然而事实

字节对齐问题详解

1.解释 字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节.字节按照一定规则在空间上排列就是字节对齐.现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2.作用和原因 各个硬件平台对存储空间的处理上

C语言字节对齐问题详解

一.何谓字节对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲,似乎对任何类型变量的访问都可以从任何地址开始,但实际情况是在访问特定变量的时候,经常在特定的内存地址访问,而不是顺序的一个接一个的排放.为了使CPU能够对变量进行快速访问,变量的起始地址应该具有某些特性,即所谓的"字节对齐".比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除. 在C语言中,结构体是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.floa

C++内存字节对齐详解

本文参考http://blog.csdn.net/arethe/article/details/2548867 一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只

struct 字节对齐详解

一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐.    对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下

C语言字节对齐问题详解【转】

引言 转自:http://www.cnblogs.com/clover-toeic/p/3853132.html 考虑下面的结构体定义: 1 typedef struct{ 2 char c1; 3 short s; 4 char c2; 5 int i; 6 }T_FOO; 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4. 现在,我们编写一个简单的程序: 1 int main(void){ 2 T_FOO a; 3 printf(