组合类型的优化

1.结构:
(1)内存的考虑:
    struct A{ char a; long b; char c; long d;};
   
    struct B{ char a; char c; long b; long d;};
 
#pragma pack(push,1) // 1 就是sizeof(char)的值
    struct C{ char a; long b; char c; long d;};
#pragma pack(pop)
 
当在Windows系统上使用Develper Studio 运行测试可得
A,B,C的大小分别是16,12,10 bytes.
 
这是因为,一般情况下,编译器强制long word与下一个long word相邻;这意味着long word的地址是4的倍数。
因此结构A的开始部分在内存中的分布情况如下:
地址                    内容
00                       字符a
01                       未用
02                       未用
03                       未用
04                       byte 0 of long b (long类型内的字节顺序随系统不同而不同)
05                       byte 1 of long b
06                       byte 2 of long b
07                       byte 3 of long b
结构B
00                       字符a
01                       字符c
02                       未用
03                       未用
04                       byte 0 of long b
05                       byte 1 of long b
06                       byte 2 of long b
07                       byte 3 of long b
结构C(因为对齐值是1,即以字符为单位对齐)
00                       字符a
01                       byte 0 of long b
02                       byte 1 of long b
03                       byte 2 of long b
04                       byte 3 of long b
05                       字符c
06                       byte 0 of long d
07                       byte 1 of long d
08                       byte 2 of long d
09                       byte 3 of long d
 
#pragma pack编译指令可以让编译器暂时调整对齐,使用push,pop能保证其它部分的对齐方式不受当前的命令影响:先用push命令把当前的对齐方式放入编译器堆栈中,然后pop命令来恢复原理的对齐方式。关于对齐方式的详细信息,可参阅所有编译器的使用手册(对于Microsoft Develop Studio,使用"/Zp"编译选项,对于GNU编译器,使用man gcc 或者 man g++)。
 
    各种类型都有自己的对齐方式(我认为称为对齐字节或则对齐单位好一些):
基本数据类型type (char,word,short,long,int,pointer,float,double,long int)的对齐方式 = sizeof(type), bitfield 的对齐方式是4 (即sizeof(long word)),struct和union的对齐方式是其最大size的成员类型的对齐方式。
 
注意:有些处理器在使用奇数地址时存在困难。如果移植使用对齐调整后的代码,程序内存占用情况就会发生变化,甚至变量存取速度会减慢。因此,对齐调整是属于特定系统内优化的问题,肯定会受目标系统的限制。
 
2.bitfield
 
比特域使用较为极端的变量对齐方式。C++的比特域允许在一个基本类型内定义数个变量,从而充分利用基本类型的各个比特位。
假设需要创建包含6个变量的数据库元素,其中4个大小范围是0~2031,另2个范围是0~1011。
struct NotBitField{
short  A,B,C,D;
short  E,F;
};
在内存中占用的空间大小是12个字节。
 
struct BitField{
unsignd A :11;
unsignd B :11;
unsignd E :10;
unsignd C :11;
unsignd D :11;
unsignd F :10;
};
由于编列合理,就把整个结构压缩在2个long word中,因此结构大小是8个字。
注意,在前面的“结构”一节中已经说明了, bitfield的对齐方式是4个字节,即是以long word为单位排列。
如果排列不佳,比如:
struct WastingBitField{
unsignd A :11;
unsignd B :11;
unsignd C :11;
unsignd D :11;
unsignd E :10;
unsignd F :10;
};
因为A B就占用了22个比特位,而A B C一共需要占用33个,因此,系统不得不让A B 占用1个字节,而让C重新开始占用1个字节,这样就造成10个bit的浪费,因此实际上WastingBitField的大小是12个字节。
 
(2)速度的考虑
实际上,强制处理变量存放边界时非常有意义的,在设计比特域时仔细考虑一下,就可以充分利用内存空间;同时,由于变量集中存放,编译器可以生成速度比较快的代码。
比特域赋值最多需要2步比特操作。
但我们并不是总使用常量值或者编译器在编译时可以获取常量数值。当使用常量给比特域赋值或与其进行算术运算时,就会产生更多的开销。
因此,在使用的时候就要根据实际的需要折中速度和内存。
 
(3)陷阱
struct FaultyBitField{
   unsigned a, b : 4;//错误
};并未创建2个4位比特域,仅仅是b为4位比特。
正确的方式是unsigned a :4,b:4;
 
可以在一个结构中同时包含比特域和基本类型,但最好不要这样:
struct CombinedFields{
  char a;
  unsigend b:4;
};
不幸的是,不论基本类型是在比特域前还是后,它们都会存放在不同的long word中;因此,用unsingd a : 8;代替char a;更好,这样整个结构就放到同一个long word中(再提醒:比特域中是使用long word为基本单位)。
 
3.联合
    当每次只需要用到数个变量中的一个时,使用联合(union)可使它们共享一块内存区。因此,联合的大小就是它所包含的最大元素的大小。
当联合元素的大小相差不多时,联合市节省内存空间的理想工具,同时能够进行严格的类型检查;但当元素大小相差很大时,需要重新考虑是否使用联合。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值