打印

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

[复制链接]
2297|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
pyj0314|  楼主 | 2008-12-3 10:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下是《嵌入式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协议斩,不让用联合,也不让用指针类型转换??!!有什么更好的方法么??

相关帖子

沙发
mxh0506| | 2008-12-3 10:50 | 只看该作者

是啊,需要自己控制endian的时候比较麻烦

使用特权

评论回复
板凳
djyos| | 2008-12-3 16:44 | 只看该作者

我一般是限制使用联合体

在两种情况下,我会使用联合体:
union aaa
{
    成员A;
    成员B;
};
1、联合体内各成员不交互解释的情况,即某联合变量,要么只按成员A访问,要么只按成员B访问,中间没有交叉。例如:
//用于信号量和互斥量共享内存池
union lock_mem_block
{
    struct semaphore sem;
    struct st_mutex  mut;
};
如果某个锁被作为信号量创建,则永远按信号量访问,如果作为互斥量创建,则永远按互斥量访问。

2、数据的内容只按其中一个成员解释,包括隐含的和明示的解释。例如
union file_attrs
{
    uint8_t all;
    struct file_attr_bits bits;
};
其中all成员仅仅用于把所有位清零或者置1,不对位成员的存储位置做任何解释。

使用特权

评论回复
地板
xwj| | 2008-12-3 17:40 | 只看该作者

我也不能理解

使用特权

评论回复
5
菜人菜语| | 2008-12-3 18:34 | 只看该作者

MISRA是关于可靠性的,是个经验性的东西

就象前人说“轻诺者必寡信”,这不是个规律,但你依循它,会有潜在的好处。

MISRA也一样,你也可以不遵守,但遵守了,在某些时候,会显现出它的好处。

关于联合体,个人猜想可能有两个方面,一是在不同的编译器、不同体系CPU之间移植代码的时候,有可能遇到问题;另外,从联合体的使用上,如a.b.c, a.c.d,代码阅读者无法直观地区分是结构还是联合体,在大项目中,同一段代码由不同的开发人员来共同维护的时候,有可能导致潜在的混淆。

使用特权

评论回复
6
mohanwei| | 2008-12-3 18:50 | 只看该作者

和goto一个道理,看你怎么用了。做底层没有goto怎么行……

使用特权

评论回复
7
mohanwei| | 2008-12-3 18:51 | 只看该作者

底层核心的代码几乎不存在移植的问题……

使用特权

评论回复
8
goosen| | 2008-12-5 08:58 | 只看该作者

goto处理异常还是很灵活的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

7

帖子

0

粉丝