字节对齐
2015-11-03 16:47
302 查看
什么是字节对齐,为什么要对齐
现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数
据。
以下内容节选自《IntelArchitecture 32 Manual》。
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16 整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
一次访问时,要么读0x01~0x04,要么读0x05~0x08……
硬件不支持一次访问就读到0x02~0x05
举个例子,如果0x02~0x05存了一个int,读取这个int就需要先读0x01~0x04,留下0x02~0x04的内容,再读0x05~0x08,留下0x05的内容,两部分拼接起来才能得到那个int的值……
读一个int就要两次内存访问,效率就低了……
字节对齐要区分四个概念
1、 基本数据类型的自身对齐值:
1字节:char型
2字节:short型
4字节:int,float类型
8字节:doublel类型
2、程序的指定对齐值:即#pragma pack(value)时的指定对齐值value
3、自定义类型的自身对齐值:结构体或类的成员中自身对齐值最大的值
4、自定义类型的有效对齐值:自定义类型的自身对齐值和指定对齐值中较小的值
据此,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。
#pragma pack(4)
Struct test
{
Char a;
Short b;
Char c;
};
上述结构体S的自身对齐值为2(b的自身对齐值),而指定对齐值为4(32位编译器默认值),故最终的有效对齐值为2.
现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数
据。
以下内容节选自《IntelArchitecture 32 Manual》。
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16 整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
一次访问时,要么读0x01~0x04,要么读0x05~0x08……
硬件不支持一次访问就读到0x02~0x05
举个例子,如果0x02~0x05存了一个int,读取这个int就需要先读0x01~0x04,留下0x02~0x04的内容,再读0x05~0x08,留下0x05的内容,两部分拼接起来才能得到那个int的值……
读一个int就要两次内存访问,效率就低了……
字节对齐要区分四个概念
1、 基本数据类型的自身对齐值:
1字节:char型
2字节:short型
4字节:int,float类型
8字节:doublel类型
2、程序的指定对齐值:即#pragma pack(value)时的指定对齐值value
3、自定义类型的自身对齐值:结构体或类的成员中自身对齐值最大的值
4、自定义类型的有效对齐值:自定义类型的自身对齐值和指定对齐值中较小的值
据此,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。
#pragma pack(4)
Struct test
{
Char a;
Short b;
Char c;
};
上述结构体S的自身对齐值为2(b的自身对齐值),而指定对齐值为4(32位编译器默认值),故最终的有效对齐值为2.
相关文章推荐
- IE7降低内存和降低CPU的几个技巧
- 如何高效的使用内存
- DOS下内存的配置
- Lua和C语言的交互详解
- XP/win2003下发现1G的内存比512M还慢的解决方法
- PowerShell实现动态获取当前脚本运行时消耗的内存
- C#实现把dgv里的数据完整的复制到一张内存表的方法
- SQL语句实现查询SQL Server内存使用状况
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构