数据对齐,有效对齐值(转载)

一、什么是对齐,以及为什么要对齐:

1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。

二、对齐的实现

通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。
但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。
对齐的算法:
由于各个平台和编译器的不同,现以本人使用的gcc version 3.2.2编译器(32位x86平台)为例子,来讨论编译器对struct数据结构中的各成员如何进行对齐的。
设结构体如下定义:
struct A {
    int a;
    char b;
    short c;
};
结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个。所以A用到的空间应该是7字节。但是因为编译器要对数据成员在空间上进行对齐。
所以使用sizeof(strcut A)值为8。
现在把该结构体调整成员变量的顺序。
struct B {
    char b;
    int a;
    short c;
};
这时候同样是总共7个字节的变量,但是sizeof(struct B)的值却是12。
下面我们使用预编译指令#pragma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。
#progma pack (2) /*指定按2字节对齐*/
struct C {
    char b;
    int a;
    short c;
};
#progma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(struct C)值是8。

修改对齐值为1:
#progma pack (1) /*指定按1字节对齐*/
struct D {
    char b;
    int a;
    short c;
};
#progma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(struct D)值为7。

对于char型数据,其自身对齐值为1,对于short型为2,对于int,float类型,其自身对齐值为4单位字节,double自身对齐值为8。
这里面有四个概念值:
1)数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。

2)指定对齐值:#pragma pack (value)时的指定对齐值value。

3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。

4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。

有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是 数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍,结合下面例子理解)。这样就不难理解上面的几个例子的值了。
例子分析:
分析例子B;
struct B {
    char b;
    int a;
    short c;
};
假设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:
#pragma pack (2) /*指定按2字节对齐*/
struct C {
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/
第一个变量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进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙的出了一些错,很难排查。

转载:http://blog.csdn.net/arethe/article/details/2548867

时间: 2024-10-11 05:04:12

数据对齐,有效对齐值(转载)的相关文章

数据对齐详解(转载)

数据对齐实际上是内存字节的对齐,今天偶然翻开自己以前做的笔记,发现做了好多的题,但现在对于我来说觉得很陌生.上网查了一下数据对齐的原因和方式,现在把它整理出来以备之后的学习复习巩固. 一.什么是数据对齐 1.现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2.访问数据的地址要满足一定的条件,能被这个

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

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

C结构体中数据的内存对齐问题

转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一般默认8字节对齐(64位机机器字长8字节) 1.先看下面的例子:struct A{   char c1;   int i;   short s;   int j;}a; struct B{   int i;   int j;     short s;   char c1;}b; 结构A没有遵守字节对

sk_buff的数据预留和对齐

转自:http://blog.csdn.net/keepmovingnow/article/details/45850387 数据预留和对齐主要由skb_reserve().skb_put().skb_push()以及skb_pull()这几个函数来完成. 1.skb_reserve() skb_reserve()在数据缓存区头部预留一定的空间,通常被用来在数据缓存区中插入协议首部或者在某个边界上对齐.它并没有把数据移出或移入数据缓存区,而只是简单地更新了数据缓存区的两个指针-分别指向负载起始和

数据对齐/内存对齐 && 数据格式

一.数据对齐/内存对齐 字.双字.四字在自然边界上不需要在内存中对齐.(什么叫做字?见第二部分) 对字.双字.四字来说,自然边界分别是偶数地址.可以被4整除的地址.可以被8整除的地址. 无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐. 原因在于,为了访问未对齐的内存,处理器需要做两次内存访问:然而,对齐的内存仅需要一次访问. 未对齐的:一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,需要两次总线周期访问内存. 对齐的:一个

为什么要进行内存对齐以及对齐规则

#include<iostream> using namespace std; struct A{ char a; int b; short c; }; struct B{ short c; char a; int b; }; int main(){ cout<<sizeof(A)<<endl; cout<<sizeof(B)<<endl; return 0; } 以上结构体变量数量类型相同.但是sizeof却不同, sizeof(A) is 1

解决echarts的叠堆折线图数据出现坐标和值对不上的问题

原文:https://blog.csdn.net/qq_36538012/article/details/88889545 ------------------------------- 说一个小bug,解决echarts的叠堆折线图数据出现坐标和值对不上的问题. 在echarts的叠堆折线图中,有这样的一个问题,从后端请求过来的数据是正确的,但是请求的y轴的值和y轴坐标对不上. 这个时候,查看了一下代码,因为是三条折线叠堆,打开代码看了一下属性发现stack的值都是一样的,因此,出现了这样的b

View从Action中获得数据和html helper function(转载)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

基于内容的数据迁移计划和方案--转载

越来越多的企业用内容管理系统来管理电子发票,电子文档,人力资源等结构化或非结构化数据内容,而且把这些业务外包到第三方的 IT 公司.外包公司的更换,或者现有内容管理系统不能满足业务增长,性能,兼容性等方面的需要,企业计划采用业务管理,性能以及兼容性更好的系统. 还有的企业目前根本没有采用内容管理系统,所有的发票,电子文档,人力资源信息都是以纸质文字或者档案的形式管理维护,为了提高企业的运营效率,这些企业计划采用内容管理解决方案. 如何在不干扰现有业务的基础上把这些内容数据从一个系统迁移到另外一个

VBS 移除excel数据公式,只保留值

如果将excel数据公式移除,只保留计算之后的值,将大大减少excel文件. 因为有上篇移除excel外部数据链接的经验,进行excel数据公式移除将快的多,方法如下. 首先我们得明白怎么手动移除excel的格式. 选中要处理的数据,然后右击 copy, 再右击paste Special,然后出现如下图的提示框.选中 Values. 此时要处理的数据将只以值呈现,格已去掉. 然后通过宏录制,来查看用的什么函数,发现VBA用PasteSpecial来处理. 接下来在搜索VBA函数. 内容如下: 应