源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

C/C++数据对齐详细解析

  • 时间:2020-12-28 18:43 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:C/C++数据对齐详细解析
Data Alignment 关于数据对齐问题,现在多多少少有了一些接触,简单地说下自己的看法。 [b]1、对齐的背景[/b] 大端和小端的问题有必要在这里介绍一下,计算机里面每个地址单元对应着一个字节,一个字节为8bit,对于位数大于8位的处理器来说,寄存器的宽度是大于一个字节的,例如16bit的short型变量x,在内存中的地址是0x0010,x的值为0x1122,0x11为高字节,0x22为低字节,常用的X86结构是小端模式,很多ARM,DSP都是小端模式,而KEIL C51则为大端模式。内存空间是按照byte进行划分的,理论上对任何类型的变量的访问可以从任何地址开始,但实际上访问特定变量的时候经常在特定的内存地址访问,这就需要各类型的数据按照一定的规则在空间上排列,而不是顺序排列,这就是对齐。 [b]2、对齐的原因[/b] 不同硬件平台对存储空间的处理是有很大不同的,一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。 [b]3、对齐的实现[/b] 通常我们在写代码的时候是不需要考虑对齐的影响的,都是依赖编译器来为我们选择适合的对齐策略,我们也可以通过传递给编译器预编译指令来指定数据对齐的方法。 以struct数据结构的sizeof方法为例,环境是Mac OS X 64位内核,结构体的定义如下: struct A { int a; char b; short c; }; struct B { char b; int a; short c; }; #pragma pack(2) struct C { char b; int a; short c; }; #pragma pack() #pragma pack(1) struct D { char b; int a; short c; }; #pragma pack() int main(int argc, char** argv) { printf("size of struct A : %lu \n", sizeof(struct A)); printf("size of struct B : %lu \n", sizeof(struct B)); printf("size of struct C : %lu \n", sizeof(struct C)); printf("size of struct D : %lu \n", sizeof(struct D)); return 0; } 输出: size of struct A : 8 size of struct B : 12 size of struct C : 8 size of struct D : 7 结构体中包含了4字节长度的int一个,1字节长度的char一个以及2字节长度的short一个。加起来所用到的内存空间为7个字节,但实际使用sizeof时发现,结构体之间占用的内存是不一样的。 [b]关于对齐有几个需要说明的: [/b](1)数据类型自身的对齐值:基本数据类型的自身对齐值,char类型为1,short类型为2,int,float,double为4; (2)指定对齐值:#pragma pack(value)时的指定对齐值value; (3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值; (4)数据成员、结构体和类的有效对齐值:自身对齐值或指定对齐值中较小值。 对于一个具体的数据结构的成员和其自身的对齐方式,有效对齐值N将最终决定数据存放地址的方式的值,对齐在N上就意味着数据“存放的起始地址%N=0”, 下面来针对上面的例子进行分析: struct B { char b; int a; short c; }; 假设B从地址空间0x0000开始,默认的对齐值是4(这里有个问题想请教大家,我的是64位的内核,但是测试我的默认对齐方式为4),第一个成员变量b的自身对齐值为1,比默认值小所以有效对齐值为1,存放地址0x0000%1=0,第二个成员变量a,自身对齐值为4,存放的起始地址为0x0004到0x0007这个4个连续的字节空间中,0x0004%4=0,第三个变量c,自身对齐值为2,存放的起始地址为0x0008到0x0009,地址同样符合要求。结构体B的自身对齐值为变量中的最大对齐值(b)4,(10+2)%4=0,所以0x000A到0x000B也是被结构体B占用。 内存中的示意图: b - - - a a a a c c #pragma pack(2) struct C { char b; int a; short c; }; #pragma pack() 第一个变量b的自身对齐值为1,指定对齐值为2,有效对齐值为1,b存放在0x0000,a的自身对齐值为4,大于指定对齐值,所有有效的对齐值为2,a占有的字节为0x0002、0x0003、0x0004、0x0005四个连续字节中,c的自身对齐值为2,所以有效对齐值也是2,顺序存放在0x0006、0x0007。结构体C的自身对齐值为4,所以有效对齐值为2,8%2=0。 内存中的示意图: b - a a a a c c 其实想到内存中的示意图一切都会简单很多。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部