关于MISRA:规则 18.4 不允许使用联合体

zhengkangshan   2008-12-3 10:07 楼主
以下是《嵌入式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协议斩,不让用联合,也不让用指针类型转换??!!有什么更好的方法么??

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复