- 浏览: 26662 次
- 性别:
- 来自: 深圳
最新评论
一、什么是对齐,以及为什么要对齐:
1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
二、对齐的实现
通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。
但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。
对齐的算法:
由于各个平台和编译器的不同,现以本人使用的gcc version 3.2.2编译器(32位x86平台)为例子,来讨论编译器对struct数据结构中的各成员如何进行对齐的。
设结构体如下定义:
1 <SPAN>struct A {
2 int a;
3 char b;
4 short c;
5 };
6 </SPAN>
结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个。所以A用到的空间应该是7字节。但是因为编译器要对数据成员在空间上进行对齐。
所以使用sizeof(strcut A)值为8。
现在把该结构体调整成员变量的顺序。
1 struct B {
2 char b;
3 int a;
4 short c;
5 };
这时候同样是总共7个字节的变量,但是sizeof(struct B)的值却是12。
下面我们使用预编译指令#pragma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。
1 #progma pack (2) /*指定按2字节对齐*/
2 struct C {
3 char b;
4 int a;
5 short c;
6 };
7 #progma pack () /*取消指定对齐,恢复缺省对齐*/
8 //sizeof(struct C)值是8。
修改对齐值为1:
1 #progma pack (1) /*指定按1字节对齐*/
2 struct D {
3 char b;
4 int a;
5 short c;
6 };
7 #progma pack () /*取消指定对齐,恢复缺省对齐*/
8 sizeof(struct D)值为7。
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
这里面有四个概念值:
1)数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。
2)指定对齐值:#pragma pack (value)时的指定对齐值value。
3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是 数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍,结合下面例子理解)。这样就不难理解上面的几个例子的值了。
例子分析:
分析例子B;
1 struct B {
2 char b;
3 int a;
4 short c;
5 };
假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指 定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为 4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐 值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存 放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求, 0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B 共有12个字节,sizeof(struct B)=12;
同理,分析上面例子C:
1 <SPAN>#pragma pack (2) /*指定按2字节对齐*/
2 struct C {
3 char b;
4 int a;
5 short c;
6 };
7 #pragma pack () /*取消指定对齐,恢复缺省对齐*/
8 </SPAN>
第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么 b存放在0x0000,符合0x0000%1= 0;第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续 字节中,符合0x0002%2=0。第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放
在0x0006、0x0007中,符合 0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。又C的自身对齐值为4,所以 C的有效对齐值为2。又8%2=0,C只占用0x0000到0x0007的八个字节。所以sizeof(struct C)=8.
有 了以上的解释,相信你对C语言的字节对齐概念应该有了清楚的认识了吧。在网络程序中,掌握这个概念可是很重要的喔,在不同平台之间(比如在Windows 和Linux之间)传递2进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙的出了一些错,可是很难排查的
发表评论
-
网络编程——一些思考
2013-05-09 15:07 5251. 在学习网络编程的时候,我通过网上的了解,买了不少书, ... -
centos中编译log4cxx
2013-03-18 10:10 1573log4cxx-0.10.0日志中文乱码 log4cxx ... -
linux在用户程序中如何向操作系统发送按键事件
2013-01-23 19:09 2554转自:http://blog.csdn.net/xian ... -
为什么linux下多线程编程,每次执行结果都不一样
2013-01-03 21:41 1206#include <pthread.h> ... -
BlockingQueue C++实现
2012-11-18 21:05 1672// BlockingQueue.h: interfac ... -
27种设计模式C++实现——单例模式
2012-09-25 22:02 01. 单例模式 -
27种设计模式C++实现——原始模型模式
2012-09-25 22:01 7121. 克隆接口 2. 具体实现者类 -
27种设计模式C++实现——建造者模式
2012-09-25 21:59 10461. 指导者类 2. 抽象建造者类 3. 具体建造者类 ... -
27种设计模式C++实现——抽象工厂
2012-09-25 21:57 11921. 抽象产品类 2. 具体产品类 3. 抽象工厂 4. ... -
27种设计模式C++实现——工厂方法
2012-09-25 21:55 6731. 抽象产品类 2. 具体产品类 3. 工厂接口 4. ... -
27种设计模式C++实现——简单工厂
2012-09-25 21:54 653简单工厂 1. 抽象产品类 2. 具体产品类 3. ... -
面向对象编程<继承覆盖>之——C++
2012-09-23 21:39 698C++面向对象继承,虚方法,类似于指针..... ... -
windows进程同步
2012-09-21 15:40 9211. 进程同步的思想很简单 操作系统所有进程,都是内核 ... -
C++
2012-09-18 11:30 01. 学会数据分层,例如串口指令,与硬件业务分离 2. 学会 ... -
Java与C++内存回收浅析
2012-09-17 11:12 0java与C++内存回收浅析 内存分配结构 ... -
函数如何返回struct或class对象
2012-07-16 16:28 586所有的C、C++教科书都警 ... -
MFC Activex与JavaScript的接口交互
2012-06-18 15:06 1251在Activex的应用中与网页的JavaScript的交互必不 ...
相关推荐
### C语言字节对齐详解 #### 一、什么是对齐,以及为什么要对齐 现代计算机内存是由一个个字节组成的,理论上来说,任何类型的变量都可以从任意地址开始存放。但在实际操作中,为了提高访问效率,不同的数据类型...
理解内存对齐至关重要,因为它直接影响到程序的性能和跨平台兼容性。 首先,我们要明白什么是内存对齐。在计算机系统中,内存是以字节为基本单位进行分配的,但并不是所有数据都可以从任意地址开始存储。为了优化...
C语言字节对齐问题详解 C语言中的字节对齐问题是指在编译器将C语言程序编译成机器代码时,对变量的存储方式进行调整,以提高存取效率和减少存储空间。字节对齐是指在内存中将变量按照一定的规则排列,以便在访问...
内存对齐详解 内存对齐是计算机科学中一个重要的概念,它关乎程序在不同的硬件平台上运行时的可移植性和性能问题。在本文中,我们将深入探讨内存对齐的原因、对齐规则、试验结果,以帮助读者彻底理解内存对齐的机理...
C 结构体对齐详解是指在 C 语言中,结构体数据成员的内存对齐方式。结构体数据成员的内存对齐是指结构体成员在内存中的存放位置,需要满足某个对齐模数的要求,以便简化处理器与内存之间的数据传输,并提高读取速度...
C语言中的数据存储对齐是编译器为了提高内存访问效率和硬件兼容性而采用的一种策略。它涉及到如何在内存中安排数据结构的各个成员,确保数据读取和写入时能够快速高效地进行。对齐规则主要有以下几点: 1. **成员按...
### 内存对齐原理详解 #### 一、什么是内存对齐? 在计算机科学中,内存对齐(Memory Alignment)是指数据类型与内存地址之间的关系。简单来说,就是指数据结构(尤其是结构体中的成员)在内存中的起始地址应该...
C语言内存字节对齐详解 在C语言中,内存字节对齐是指编译器为了提高程序执行效率和可移植性,而对结构体成员在内存中的存储方式进行的调整。这个调整是基于体系结构的对齐规则,旨在提高程序的执行效率和可移植性。...
C语言中的字节对齐详解 字节对齐是一种内存存储方式,在现代计算机中,内存空间都是按照byte划分的。在理论上讲,似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定...
深入内存对齐的详解 内存对齐是计算机编程中一个非常重要的概念,它直接影响着程序的性能和可读性。本文将深入探讨内存对齐,分析其原因和实现原理,并讨论相关的编程技术。 一、内存对齐的原因 在编程中,我们...
### C++内存对齐原理与实践 #### 一、引言 在C++编程中,内存对齐(Memory Alignment)是一项重要的技术,它涉及到如何在内存中存储数据以提高程序的运行效率。良好的内存对齐不仅可以减少数据访问的时间,还可以...
### C语言中的字节对齐详解 #### 一、引言 字节对齐是C语言编程中的一个重要概念,尤其在处理复杂数据结构时尤为重要。本文将深入探讨字节对齐的基本原理、目的以及如何在实际开发中进行合理配置。 #### 二、字节...
此外,内存碎片问题及其解决方法,如内存对齐、紧凑等也是讨论的重点。书中可能还会介绍如何使用工具如`free`、`top`、`vmstat`、`sar`等监控内存使用情况,以及`strace`和`gdb`等工具调试内存问题。 在嵌入式环境...
### 字节对齐详解 #### 什么是对齐及其重要性 对齐,即**字节对齐**,是指在计算机内存中,数据按照一定规则在内存空间中的排列方式,以提高数据访问效率。理论上,任何类型的变量可以从任意内存地址开始访问,但...
内存对齐是编程中一个重要的概念,特别是在C和C++这样的低级语言中。它涉及到计算机硬件、编译器和程序性能优化等多个方面。本文将深入解析C语言和C++中的内存对齐问题。 首先,内存对齐的主要目的是提高程序执行的...