| 
 
| 以下是《嵌入式C 标准研究报告》中关于MISRA对联合体的使用约束说明 
 规则 18.4 不允许使用联合体
 这事一个不太近情理的规定,在具体阐述为何MISRA-C:2004如此痛恨联合体之前,首先需要明确与联合体相关的细节:
 1)联合体的末尾有多少个填充单元
 2)联合体的各个成员如何对齐
 3)多字节的数据类型高低字节如何排放顺序
 4)如果包含位字段 (bit-field),各位如何排放
 
 针对细节3举个例子
 程序段2.1
 
 typedef union{
 uint32_t word;
 uint8_t bytes[4];
 }word_msg_t;
 
 uint32_t read_msg(void)
 {
 word_msg_t tmp;
 /* tmp.byte[0] 对应于tmp.word的高8位
 tmp.byte[1]对应于tmp.word的次高8位,依此类推 */
 tmp.bytes[0]  = read_byte();
 tmp.bytes[1]  = read_byte();
 tmp.bytes[2]  = read_byte();
 tmp.bytes[3]  = read_byte();
 return (tmp.word);
 }
 
 
 以上代码在各种通信协议中使用的频率很高,接收端接收到的数据一般都以字节为单位存放,主控程序需要根据相应的协议将接受到的多个字节进行组合。为了实现相同的功能,MISRA-C:2004推荐恶劣read_msg()函数的另外一种写法.
 
 程序段2.2
 
 uint32_t read_msg(void)
 {
 uint32_t word;
 word = ((uint32_t)read_byte() ) < < 24;
 word = word | (((uint32_t)read_byte()) < < 16);
 word = word | (((uint32_t)read_bytes()) < < 8);
 word = word | ((uint32_t)read_byte());
 return (word);
 }
 无论从程序的可读性还是从执行效率来讲,程序段2.1都要优于程序段2.2。然而,程序段2.1在Intel 80x86/Pentium体系(little-endian,存储多字节整数的时候低位字节存放在低地址)CPU和在Motorola 68K体系(big-endian)中的执行结果完全不一样。假设read_byte()函数返回的数据依次是0x01,0x02,0x03,0x04,则在Intel体系中,程序段2.1 read_msg返回的值是0x4321,在Motorola体系中,返回的则是0x1234.    无论在Intel体系还是在Motorola体系中,程序段 2.2 中read_msg的返回值都是0x1234
 
 这样的话在处理通信协议的时候真的是很麻烦了,比如我要写一个TCP/IP协议斩,不让用联合,也不让用指针类型转换??!!有什么更好的方法么??
 | 
 |