pyj0314 发表于 2008-12-3 10:45

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

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

mxh0506 发表于 2008-12-3 10:50

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

djyos 发表于 2008-12-3 16:44

我一般是限制使用联合体

在两种情况下,我会使用联合体:<br />union&nbsp;aaa<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;成员A;<br />&nbsp;&nbsp;&nbsp;&nbsp;成员B;<br />};<br />1、联合体内各成员不交互解释的情况,即某联合变量,要么只按成员A访问,要么只按成员B访问,中间没有交叉。例如:<br />//用于信号量和互斥量共享内存池<br />union&nbsp;lock_mem_block<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;semaphore&nbsp;sem;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;st_mutex&nbsp;&nbsp;mut;<br />};<br />如果某个锁被作为信号量创建,则永远按信号量访问,如果作为互斥量创建,则永远按互斥量访问。<br /><br />2、数据的内容只按其中一个成员解释,包括隐含的和明示的解释。例如<br />union&nbsp;file_attrs<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;uint8_t&nbsp;all;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;file_attr_bits&nbsp;bits;<br />};<br />其中all成员仅仅用于把所有位清零或者置1,不对位成员的存储位置做任何解释。

xwj 发表于 2008-12-3 17:40

我也不能理解

菜人菜语 发表于 2008-12-3 18:34

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

就象前人说“轻诺者必寡信”,这不是个规律,但你依循它,会有潜在的好处。<br /><br />MISRA也一样,你也可以不遵守,但遵守了,在某些时候,会显现出它的好处。<br /><br />关于联合体,个人猜想可能有两个方面,一是在不同的编译器、不同体系CPU之间移植代码的时候,有可能遇到问题;另外,从联合体的使用上,如a.b.c,&nbsp;a.c.d,代码阅读者无法直观地区分是结构还是联合体,在大项目中,同一段代码由不同的开发人员来共同维护的时候,有可能导致潜在的混淆。<br />

mohanwei 发表于 2008-12-3 18:50

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

mohanwei 发表于 2008-12-3 18:51

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

goosen 发表于 2008-12-5 08:58

goto处理异常还是很灵活的

页: [1]
查看完整版本: 关于MISRA规则 18.4 不允许使用联合体