在嵌入式开发中,经常需要表示各种系统状态,位结构体的出现大大方便了我们,尤其是在进行一些硬件层操作时。但是在使用位结构体的过程中,有没有深入思考一下它的相关属性?有没有真正用到它的便利性,来提高系统效率?
下面我将进行一些相关实验(这里以项目开发中的实际代码为例):
1.位结构体类型设计
- //data structure except for number structure
- typedef struct symbol_struct
- {
- uint_32 SYMBOL_TYPE :5; //data type,have the affect on "data display type"
- uint_32 reserved_1 :4;
- uint_32 SYMBOL_NUMBER :7; //effective data number in one element
- uint_32 SYMBOL_ACTIVE :1;//symbol active status
- uint_32 SYMBOL_INDEX :8; //data index in norflash,result is related to "xxx_BASE_ADDR"
- uint_32 reserved_2 :8;
- }SYMBOL_STRUCT,_PTR_ SYMBOL_STRUCT_PTR;
分析:
这里定义了一个位结构体类型SYMBOL_STRUCT,那么用该类型定义的变量都哪些属性呢?看下面运行结果:
WORDS是定义的另一个外层类型定义封装,这里可以把它当作变量来看待。WORDS变量里前5个变量地址都是0x1ffff082c,最后reserved_2地址0x1fff0830,紧接着下一个PressureState变量0x1fff0834。
本来是假设reserved_1和SYMBOL_TYPE不在一个地址上的,因为他们5+4共9位,超过了1个字节地址,但这里发现他们公用首地址了;而且reserved_2竟然实际占用了4个字节(0x1fff0834 - 0x1fff0830),我本来是想让他占用1个字节的。WORDS整体占了8个字节(0x1fff0834 - 0x1fff082c),设计时分析占用5个字节(SYMBOL_TYPE 1个;reserved_1 1个;SYMBOL_NUMBER+SYMBOL_ACTIVE 1个;SYMBOL_INDEX 1个;reserved_2 1个)。中间一定有什么没有预想到的问题。
uint_32 reserved_2:8;占用4个字节,估计是uint_32在起作用,而这里写的8位,只是我使用的有效位数,另外24位空闲,如果在下面再定义一个reserved_3:8,地址也是一样的,都是以uint_32为单位取地址。
同理,上面的5个变量,共用一个地址就不足为奇了。而且有效位的分配不是连续进行的,例如SYMBOL_TYPE+reserved_1 共9位,超过了一个字节,索性系统就分配两个字节给他们,每人一个;SYMBOL_NUMBER+SYMBOL_ACTIVE 共8位,一个字节就能搞定。
2、修改数据结构,验证上述猜想
- //data structure except for number structure
- typedef struct symbol_struct
- {
- uint_8 SYMBOL_TYPE :5; //data type,have the affect on "data display type"
- uint_8 reserved_1 :4;
- uint_8 SYMBOL_NUMBER :7; //effective data number in one element
- uint_8 SYMBOL_ACTIVE :1; //symbol active status
- uint_8 SYMBOL_INDEX :8; //data index in norflash,result is related to "xxx_BASE_ADDR"
- uint_8 reserved_2 :8;
- }SYMBOL_STRUCT,_PTR_ SYMBOL_STRUCT_PTR;
地址数据如下:
当换成uint_8后,可以看到地址空间占用大大减小,reserved_2只占用1个字节(0x1fff069f - 0x1fff069e),其他变量也都符合上面的结论猜想。
总结:
1、在操作位结构体时,要关注变量的位域是否在一个uint_8上,判断占用空间大小
2、除了位域,还要关注变量定义类型,因为编译器空间分配始终是按类型分配的,位域只是指出了有效位(小于类型占用空间),而且如果位域大于类型空间,编译器直接报错(如 uint_8 test :15,可自行实验)。
3、这两个因素都影响变量占用空间大小,具体可以结合调试窗口,通过地址分配分析判断