目录
Rule 1.1 程序不应包含任何违反标准C语法和约束的内容,也不应超过实现的转换限制
一、MISRA C_2012介绍
先摘录一段百度百科里的说法:
MISRA C是由汽车产业软件可靠性协会(MISRA)提出的C语言开发标准。其目的是在增进嵌入式系统的安全性及可移植性。针对C++语言也有对应的标准MISRA C++。
MISRA C一开始主要是针对汽车产业,不过其他产业也逐渐开始使用MISRA C:包括航天、电信、国防、医疗设备、铁路等领域中都已有厂商使用MISRA C。
MISRA C的第一版《Guidelines for the use of the C language in vehicle based software》是在1998年发行,一般称为MISRA-C:1998.。MISRA-C:1998有127项规则,规则从1号编号到127号,其中有93项是强制要求,其余的34项是推荐使用的规则。
在2004年时发行了第二版的MISRA C的第一版《Guidelines for the use of the C language in critical systems》(或称作MISRA-C:2004),其中有许多重要建议事项的变更,其规则也重新编号。MISRA-C:2004有141项规则,其中121项是强制要求,其余的20项是推荐使用的规则。规则分为21类,从“开发环境”到“运行期错误”。
2012年发布第三版,为当前最新有效的C语言规范版本,称为MISRAC:2012。
MISRA版本
发布年份
C语言版本
指令 数量
规则 数量
指南 总数
1998
1998
C90
不详
127
不详
2004
2004
C90
不详
142
不详
2012
2012
C99
16
143
159
2012 AMD-1
2016
C99
17
156
173
2012 AMD-2
2020
C11
17
158
175
Misra C不能100%保证程序不出问题,但是能尽可能的预防,总结一下,基本上使用Misra C具有以下五个维度的优势:
- 提升可靠性
- 提升可读性
- 提升可移植性
- 提升可维护性
- 提升安全性
若要保证我们的程序能符合Misra C编码规范,一方面是在开发初期写代码的时候尽量按照Misra C规范来写,一方面是在后期通过一些代码检测工具来检测我们的代码是否符合Misra C规范。
因此我们平时要多积累一些Misra C规范的约束经验,尽量在后期检测中少出一些问题,毕竟出了问题还要花时间来重新翻规范重新改。
二、MISRA C_2012每条规则翻译、解读、示例
在这里我只翻译和解读158条规则,一些重要的规则尽量给出正确的示例,个人能力有限,因此不保证翻译的准确性,主要还是用于自己能更加的熟悉规则,能直接开发出符合规范的代码,当然,这个工作不是一天能完成的,反正我有空就会在这里更新的。
Rule 1系列,标准C环境准则
Rule 1.1 程序不应包含任何违反标准C语法和约束的内容,也不应超过实现的转换限制
- 原文:Rule 1.1 The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation’s tr anslation limits
- 级别:低
- 解读:程序只能使用C语言及其库中所选标准版本中指定的特性
- 示例:比如你用C90的编译器你就要符合C90的规则和特性,而不能去使用到C11的特性,其实即使你使用了,编译器也不支持,但不一定都能检测出来,具有一定的风险
Rule 1.2 不应使用语言扩展
- 原文:Rule 1.2 Language extensions should not be used
- 级别:低
- 解读:不要用编程语言扩展属性,否则会降低程序的可移植性
- 示例:无
Rule 1.3 不应出现未定义或关键的未指定行为
- 原文:Rule 1.3 There shall be no occurrence of undefi ned or critical unspecified behaviour
- 级别:中
- 解读:
任何引起未定义或未指定行为的程序都可能不以预期的方式运行。在许多情况下,这样做的结果是使程序不可移植,但也可能发生更严重的问题。例如,未定义的行为可能会影响计算的结果。如果软件的正确操作依赖于这个计算,那么系统安全可能会受到损害。如果未定义的行为只在很少的情况下出现,那么这个问题就特别难以检测。许多MISRA C指南的设计都是为了避免某些未定义和未明确的行为。例如,对规则11.4、规则11.8和规则19.2的遵守确保了在C语言中不可能创建一个非const限定的指针,该指针指向用const限定类型声明的对象。这避免了C90 Undefined 391和C99 Undefined 61。
- 示例:英文原版pdf的附录H列出了所有未定义和关键的未指定行为,以及MISRA C防止它们发生的指南。
Rule 2系列,未使用的代码的处理
Rule 2.1 项目不应该包含运行不到的代码
- 原文:Rule 2.1 A project shall not contain unreachable code
- 级别:高
- 解读:如果一个程序没有表现出任何未定义的行为,那么无法到达的代码就不能被执行,也不能对程序的输出产生任何影响。因此,无法到达的代码的存在可能表明程序逻辑中的错误。 无法到达的代码会占用目标机器的内存空间,可能会导致编译器在围绕无法到达的代码传输控制时选择更长的、更慢的跳转指令。而且在循环中,它可以防止整个循环驻留在指令缓存中。
- 示例:switch中某个case分支是永远运行不到的,程序员应该删除这种代码。
Rule 2.2 项目不应该包含死代码
- 原文:Rule 2.2 There shall be no dead code
- 级别:高
- 解读:任何可以删除掉但是不影响程序正常运行的代码都是无效代码,由于无效代码可能被编译器删除,所以它的存在可能会引起混乱。
- 示例:类似以下这种的程序永远运行不到的代码都叫无效代码。
if(0) { function(); }
Rule 2.3 项目不应该包含未使用的类型声明
- 原文:Rule 2.3 A project should not contain unused ty pe declarations
- 级别:低
- 解读:如果声明了类型但没有使用,那么审阅者就不清楚该类型是冗余的还是错误地未使用。
- 示例:使用typedef定义了一个数据类型但是从未使用过。
typedef int local_type; /* 从未使用的话将违反规则 */
Rule 2.4 项目不应该包含未使用的标签声明
- 原文:Rule 2.4 A project should not contain unused ta g declarations
- 级别:低
- 解读:如果一个标签已经声明但没有使用,那么审阅者就不清楚这个标签是多余的还是错误地没有使用。
- 示例:使用typedef定义了一个结构体类型标签或者使用enum定义了一个enum类型标签但是都从未使用过。
enum state { S_init, S_run, S_sleep }; /* 从未使用state标签的话将违反规则 */ typedef struct record_t /* 从未使用record_t标签的话将违反规则 */ { uint16_t key; uint16_t val; } record1_t; typedef struct /* 这种是可以的,不会违反规则 */ { uint16_t key; uint16_t val; } record2_t;