DSP编程技巧之12-揭开编译器神秘面纱之代码规范MISRA-C
扫描二维码
随时随地手机看文章
如果我们自己编写了一个程序,程序能正常编译,运行起来也实现了我们期望的输出,那是不是这个程序就很完善了呢?对于工业产品来说,“好”、“能用”和“完善”,或者说“标准”,甚至是代码的“安全”,显然不是一个层面的东西。因为C语言虽然是我们开发嵌入式应用的最主要工具之一,然而C语言并非是专门为嵌入式系统设计,相当多的嵌入式系统较一般计算机系统对软件安全性有更苛刻的要求;例如在那些对安全性要求很高的系统中,如飞行器、汽车和工业控制中,只要代码的工作稍有偏差,就有可能造成重大的财产损失或者人员伤亡。
那么如何衡量我们的代码是否满足某些标准,是“安全的”、“健壮的”呢?此时我们就可以根据具体的应用来查找相关的行业标准。举个例子,在工业领域中,MISRA-C就是在的某些行业中要求遵守的行业标准。MISRA C是由汽车产业软件可靠性协会(MISRA,motor industry software reliability association)提出的C语言开发标准。其目的是在增进嵌入式系统的安全性及可移植性。针对C++语言也有对应的标准MISRA C++。MISRA C一开始主要是针对汽车产业:如果我们去参加近几年的有关汽车行业的基于自动代码生成技术和基于模型的设计技术的讲座、研讨会等等,无一例外都会听到有关MISRA-C 2004,甚至是MISRA-C 2008、MISRA-C 2012等更新版本的介绍。此外,其他产业也已经逐渐开始使用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类,从“开发环境”到“运行期错误”。通常认为,如果能够完全遵守这些标准,则你的C代码是易读、可靠、可移植和易于维护的。最近很多嵌入式开发者都以MISRA C来衡量自己的编码风格,比如著名的uC/OS-II就得意地宣称自己99%遵守MISRA标准。目前有许多工具声称可以检查代码和MISRA规则相容性,不过MISRA没有相关认证的程序。相关工具可以帮助使用者评估和比较检查的结果,也会提供一些可符合MISRA-C规定的指南,但是目前大部分的工具对静态代码分析的工具检查基本能实现,对动态代码分析则还不能完美实现。
考虑到MISRA-C:2004有141项规则,其中仅强制要求就有121项,其余的20项是推荐使用的规则,显然让我们仅仅是把这么多规则浏览一遍就需要花费大量的时间,更不用提手工对照规则来检查我们的软件了。幸好我们使用的DSP编程环境CCS提供了相应的选项,使得编译器可以自动检查我们的代码是否违反了MISRA-C的相关规则,并提供给我们详细的诊断与警告信息。
在C语言的标准ANSI C 和 ISO C之后,又产生了更新的C99以及最新的C11 (ISO/IEC 9899:2011),但是因为最新版本的规范从推出到各大编译器厂家支持以及开发者的适应都需要一定的时间,所以目前最常用的仍然是ANSI C或者C99。与此类似, 虽然MISRA-C的标准最弱已经有最新的2012,但是人们谈论和使用最多的仍然是2004版本,所以在CCS的编译器选项里仍以MISRC-C:2004的规则为准。
启用了--check_misra={all|required|advisory|none|rulespec}的选项使能MISRC-C:2004规则检查之后,还可以在代码中可以配合相关的预处理指令使能某些代码的检查/停止检查功能,包括:
#pragma CHECK_MISRA ("{all|required|advisory|none|rulespec}");
#pragma RESET_MISRA ("{all|required|advisory|rulespec}");
其中,CHECK_MISRA用来使能或者禁止对MISRC-C:2004规则的检查,它的作用与--check_misra是一致的。RESET_MISRA则用来复位MISRC-C:2004规则检查的状态。
rulespec参数则可以用来指定我们使用哪些MISRC-C:2004中的哪些规则来进行特点的检查,包括:
[-]X 使能 (或者禁止) X主题下各个规则的检查。(主题包括变量、字符、初始化等)
[-]X-Z 使能 (或者禁止) 从X到Z主题下各个规则的检查
[-]X.A 使能 (或者禁止) X主题下规则A的检查。
[-]X.A-C 使能 (或者禁止) X主题下从规则A到规则C的检查。
举例说明:--check_misra=1-5,-1.1,8.2-4的含义是:
检查从主题1到主题5的规则。(不清楚的网友可以去搜索MISRA规范,1.环境;2.语言扩展;3.文档;4.字符集;5.标识符)
禁止规则1中1.1条目的规则(规则1.1(强制): 所有代码都必须遵照ISO 9899:1990 “Programming languages - C”,由ISO/IEC 9899/COR1:1995,ISO/IEC 9899/AMD1:1995,和ISO/IEC9899/COR2:1996 修订),规则1中的其它规则保持有效。
检查主题8中的规则2到4.为了方便,我们可以列出这几条规则的定义(其内容较长,有兴趣的网页请在搜索引擎中检索):
主题8: 声明与定义
规则8.2(强制): 不论何时声明或定义了一个对象或函数,它的类型都应显式声明。
规则8.3(强制): 函数的每个参数类型在声明和定义中必须是等同的,函数的返回类型也该是等同的。
规则8.4(强制): 如果对象或函数被声明了多次,那么它们的类型应该是兼容的。