数据结构,数据类型对齐

最近写软件的时候,结构体对齐的问题困扰了一段时间,收集一些资料,供大家参考:

数据对齐  

自然对齐:如果一个变量的内存地址正好是它长度的整倍数,它就被称为自然对齐。一些体系结构对对齐要求非常严格。通常想基于RISC的系统, 载入未对齐数据会导致处理器陷入(一种可处理的错误)。还有一些系统可以访问没有对齐的数据,只不过性能会下降。编写可移植性高的代码要避免对齐问题,保证所有的类型都能够自然对齐。

  

避免对齐引发的问题  

一个数据类型长度比较小,它本来是对齐的,如果你用一个指针进行类型转换,并且转换后的数据类型较长,那么通过改指针进行数据访问时就会引发对齐问题。也就是说,下面的代码是错误的:  

char dob[10];  

char *p = &dog[1];  

unsigned long l = *(unsigned long *)p;  

这个例子将一个指向char型的指针当作指向unsigned long型的指针来用,这会引起问  题,因为此时会试图从一个并不能被4整除的内存地址上载入32的unsigned long型数据。   

非标准类型的对齐       

    前面提到了,对于标准数据类型来说,它的地址只要是其长度的整数倍就对齐了。而非标准的(复合的)C数据类型按照下列原则对齐:  

1〉对于数组,只要按照基本数据类型进行对齐就可以了(其后的所有元素自然都能够对齐了)。  

2〉对于联合,只要它包含的长度最大的数据类型能够对齐就可以了。  

3〉对于结构体,只要它包含的长度最大的数据类型能够对齐就可以了。  

结构体还要引入  填补机制,这会引发下一个问题。  

 

结构体填补  

为了保证结构体中每一个成员都能够自然对齐,结构体需要被填补。举例:  

上面的代码中对于结构体 BBB 的定义如下:  

struct BBB{  

char aChar;  // 1 byte  

double aDouble; // 8 bytes  

int aInt;  // 4 bytes  

};  

由于该结构体不能准确地满足各个成员自然对齐,所以它在内存中可不是按照原样存放的。编译器会在内存中创建一个类似下面的给出的结构体:  

struct BBB{  

char aChar;  // 1 byte  

u8 __pad0[7]; // 7 bytes  

double aDouble; // 8 bytes  

int aInt;  // 4 bytes  

u8 __pad1[4]; // 4 bytes  

};   

填补的变量都是为了让数据自然对齐而加入的。__pad0 是为了让 aDouble 能够自然对齐而加入的,而其他额外的填补如 __pad1 则是为了让结构体的长度能够被最大元素(aDouble)的长度 8 整除而加入的。结构体AAA的长度为16,而不是13就是因为后一种填补引起的。通常你可以通过重新排列结构中的对象来避免填充或减少填充。像结构体AAA那样,把元素按长度的大小递减/增的排列后就可以使它占最小的空间了。  

 

注意:编译器,优化器并不能改变结构体中元素的排列次序。如ANSI C就明确规定不允  许编译器改变结构体内成员对象的次序,它总是由你--程序员来决定。  并不是所有的结构体进行这样的调整的,

比如:该结构体作为一个标准的一部分,或者  它是现有代码的一部分。   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值