Misra C 概述
1 什么是MisraC规范
大家应该听说过,很多的大公司都有自己相应的代码编程规范。针对C语言尤其严谨,比如比较著名的有:华为C语言编程规范、阿里C语言编程规范和MisraC等。但是侧重点又各有不同,各类规范可能会有交集,也有自己独特的地方存在,但是大家都是致力于让程序员能写出一手更好的代码:
- 华为、阿里的编程规范更加注重代码风格的规范
- 比如每行代码不能超过120个字、代码缩进、空格和大括号等的使用,这些是MisraC这样的规范中没有的 - MisraC更加注重代码的功能性、稳定性和可维护性
- 比如所有的switch的case里都要有break,以防止错误逻辑的意外发生
- 再比如操作符两边的数据类型需要一致,以防止隐式类型转换会发生与程序员想法不一致的情况(比如uint8类型的a就不能和int16类型的b做">"
"<"
"=="
的比较)
那什么是MisraC规范呢?我们摘录一段百度百科里的说法:
MISRA-C,汽车制造业嵌入式C编码标准,最早版本为MISRA-C:1998,该标准后来的版本增加了编码规范的覆盖范围到其他高安全性系统,当前最新版本为MISRA-C:2012
MISRA-C,汽车制造业嵌入式C编码标准
1998年汽车工业软件可靠性联合会(MISRA)发布的针对汽车工业软件安全性的C语言编码规范,成为MISRA-C:1998。此编码规范最初只是针对汽车制造业的嵌入式开发,从MISRA-C:2004开始扩大覆盖范围到其他高安全性系统,最新版本为MISRA-C:2012
这里我们不得不提到汽车行业:目前嵌入式行业里,使用嵌入式编码最多的就是汽车行业了,一辆高端汽车整车的代码行数已经突破了1亿行(不比一架飞机的代码量少)。那么如果这些代码都写得乱七八糟,试问当前看博客的朋友,你敢买吗?为了规范大家的写法,增强可读性,可维护性,减少代码可能出现的低级错误,于是MISRA协会针对C语言的MisraC规范,用于规范大家的编程,提高代码整体的可靠性。而目前由于MisraC规范的知名度越来越高,其在飞机、机器人、无人机等其他的嵌入式行业也开始推行起来,成为了全球公认的嵌入式编程规范
再说回MisraC本身,其本质就是C语言的一个子集,在本身C语言的基础上,加上了一些约束,我们可以理解为C - - (‾◡◝)。但是这个C - - 去掉的是一些容易让人出错的编程方法,保留了大家常用的写法。大家都知道C语言实现一种功能有很多的方式,对于一些容易出错的,MisraC便尽量让大家保持一致,便于排错和分析,也便于其他人的阅读和维护
2 C语言编程的痛点
C语言编程是一个开放的过程,这个过程中往往会因为各种各样的因素导致程序的运行和设想有偏差。目前没有任何一种语言可以做到能直接理解程序员心中所想,并直接转化为可运行的代码;但是对于C语言这样的偏底层的语言来讲,太过开放,可能导致的结果就是更加不可能一次就把代码写成功。我们可以将这些C语言编程的问题归纳为如下痛点:
- 程序员编码过程的失误
人非圣贤,谁人都有过将==
写成=
的经历吧,然后找半天原因,最后无意间发现了这个bug - 程序员对C语言了解不充分
C语言的内容还是不少的,编码要求我们的代码要100%按要求运行。但是实际程序员编码过程中,最常用的语法无法覆盖100%,有些语法或者用法可能好几年才会用到一次。因此,程序员可能在编码过程中产生对C语言的错误理解,导致逻辑错误。比如:运算符的优先级,大家能第一时间确认c = a + b << 1
中,+
和<<
哪个先运算吗?为了避免这类问题,MisraC要求在含混不清的代码中加上括号,比如这样:c = (a + b) << 1
来防止误解 - C语言编译器的差异导致程序运行不一致
C语言发展了很多年了,但是仍然无法避免因为编译器的不同而产生最终结果的差异,甚至背离程序员编码的初衷。因此,为了更好的代码移植性和可靠性。MisraC会有很多的规定来限制写法,保证代码在所有编译器上输出的程序都能有相同的运行结果 - 编译器本身的错误
编译器本身也是一个程序,是程序就可能会出错,编译器的编译可能会导致错误。因此减少一些编译器容易出错的写法,也可以提高代码可靠性 - 运行时的错误
C语言本身运行时检查能力比较弱,特别是一些栈溢出,超范围等的问题的检查很难定位
3 使用MisraC的优势
MisraC不能100%保证程序不出问题,但是能尽可能的预防,上面说了很多了。这里我们总结一下,基本上使用MisraC具有以下五个维度的优势:
- 提升可靠性
- 提升可读性
- 提升可移植性
- 提升可维护性
- 提升安全性
当然,MisraC不是万能的,在使用初期,程序员很可能因为修改MisraC而耽误一些时间,这时不可避免的
4 本专栏内容概览
从总目录中我们可以看到,2012规范主要分为Directives和Rule两个部分
- 指令(Directives)主要是一些不能提供执行符合性检查所需的完整描述的指导原则。为了能够进行检查,需要提供额外的信息,例如可能在设计文档或需求规范中提供的信息。静态分析工具可以帮助检查指令的遵从性,但是不同的工具可能对什么构成不遵从性有不同的解释
例子
Dir 4.9 规定: 应该优先使用函数,而不是类函数宏,因为它们是可以互换的
但是我们在程序中又会经常使用到这样的宏:#define MIN(a, b) a < b ? a: b
那究竟什么样的宏算是类函数宏,是需要人为定义的。比如长度超过10行,或者用了do{} while(0)这种语法的,而这个标准是要根据实际情况判定,在MisraC中不做具体定义
- 规则(Rule)是一个指导方针,它提供了需求的完整描述。不需要任何其他信息就可以检查源代码是否符合规则
例子
Rule 15.5 规定: 一个函数只能有一个退出条件语句,并且放在函数最后
退出条件语句也就是我们经常用的return语句,禁止多个return的使用,有利于理清楚函数的逻辑,方便阅读。而这条规则没有任何的歧义,也不用人为定义什么,MisraC已经定义的很清楚了,因此属于Rule里面
接下来,我们就要将所有的MisraC条款都为大家梳理一遍,大家可以当成工具书查看
附:返回总目录的传送门如下
->返回总目录<-