1、MISRA 2004 规则Jerry 整理出处:汽车工业软件可靠性联会最后更新时间:2005-7-20转载请注明:来自 Sawin 系统分析之窗MISRA (The Motor Industry Software Reliability Association 汽车工业软件可靠性联会) 是位于英国的一个跨国汽车工业协会,其成员包括了大部分欧美汽车生产商。其核心使命是为汽车工业提供服务和协助,帮助厂方开发安全的、高可靠性的嵌入式软件。这个组织最出名的成果是所谓的 MISRA C Coding Standard,这一标准中包括了 127 条 C 语言编码标准,通常认为,如果能够完全遵守这些标准,则
2、你的 C 代码是易读、可靠、可移植和易于维护的。最近很多嵌入式开发者都以 MISRA C 来衡量自己的编码风格,比如著名的 uC/OS-II就得意地宣称自己 99遵守 MISRA 标准。而嵌入式开发杂志也专门载文号召大家学习。编码规范通常是一个公司自定的“土政策” ,居然有人去做标准,而且还得到广泛的认可,这不禁引起我强烈的兴趣。可惜这份标准的文本需要花钱去买,而且短短几十页,要价非常昂贵。MISRA 在网上公布了一些文档,其中有关于 MISRA C Coding Standard 的 Clarification 报告,从中间你可以大致猜到 MISRA 标准本身是什么。我仔细阅读了这些文档,并
3、且通过阅读其他一些介绍性文档,大致了解了 MISRA 标准的主要内容。这些条款确有过人之处,对于 C/C+语言工程项目的代码质量管理能够起到良好的指导性作用,对于大部分软件开发企业来说,在 MISRA 的基础上适当修改就可以形成自己的规范。当然其中也有一些过于严苛的东西,这就需要各个开发部门灵活处理了。我个人的体会,编码规范虽然很简单,但是要完全执行,不折不扣,需要开发部门有很高的组织性和纪律性,并且有很好的代码评审机制。因此,如果能够严格地遵守编码规范,本身就是一个开发部门实力的证明。内容Rule1.1(强制):所有的代码应该遵守 ISO 9899:1990“Programming Lang
4、uage C”Rule1.2(强制):只有当具备统一接口的目标代码的时候才可以采用多种编译器和语言Rule1.4(强制) 检查编译器/连接器以确保支持 31 一个有效字符,支持大小写敏感Rule 2.1(强制) :汇编语言应该封装起来并且隔离:例如:#define NOP asm(“ NOP”)Rule 2.2(强制) :源代码只能采用 /*/风格的注释Rule2.3(强制): 字符序列/*不能在注释中使用注:C 语言不支持注释的嵌套即使一些编译器支持这个语言扩展Rule 2.4(建议) :代码段不能注释掉注:应采用#IF 或者#ifdef 来构成一个注释,否则代码里如果有注释会改变代码的作用
5、Rule 3.3(建议) :编译器对于整数除法运算的实施应该写入文档例编译器:-5/3 = -1 余-2 有些编译器结果是-2 于1Rule 4.1(强制) :只能使用 ISO 标准定义的字符集Rule6.5 (强制): 在内部范围的标识符不能和外部的标识符用同样的名字,因为会隐藏那个标识符例:int16_t i:Void f()int16_t i;i=3;Rule 5.2(强制): typedef 名称只能唯一,不能重复定义Rule 5.4(强制): 标记名应该是唯一的标识符Rule 5.7(建议): 标识符不能重复使用Rule 6.1(强制):Char 类型只能用来存储使用字符Rule 6
6、.2(强制):signed 和 unsigned char 只能用来存储和使用数据值Rule6.3(建议) 对于基本的类型使用 Typedef 来表示大小和有无符号例:Typedef char char_tTypedef signed int int32_t Rule 7.1(强制) :不要用八进制数注:整型常数以”0“开始会被认为是 8 进制例:code1=109code2=100code3=052code4=071如果是对总线消息初始化,会有危险Rule 8.1(强制) :函数都应该有原型声明,且相对函数定义和调用可见Rule8.2 (强制) :无论何时一个对象和函数声明或者定义,它的类型
7、应该明确声明Rule 8.5(强制): 头文件中不要定义对象或者函数Rule8.3(强制) :每个函数声明中的参数的类型应该和定义中的类型一致Rule 8.8(强制): 外部变量或者函数只能声明在一个文件中注:一般来讲,声明在头文件中,然后包含在定义和使用的文件中Rule 8.12(强制) :数组声明为外部,应该明确声明大小或者直接初始化确定例:extern int array2 /* 违反 Rule8.8 */Rule 9.1(强制): 所有变量在使用之前都应该赋值Rule 10.1(强制): 整型表达式不要隐式转换为其他类型:a)转换到更大的整型b)表达式太复杂c)表达式不是常数是一个函数
8、d)表达式不是一个常数是一个返回表达式Rule 10.2(强制) :浮点数表达式不要隐式转换为其他类型:a)转换到更大的浮点数b)表达式太复杂c)表达式是一个函数d)表达式是一个返回表达式Rule 10.3(强制): 整型表达式的值只能转换到更窄小且是同样符号类型的表达式Rule 10.4(强制): 浮点表达式的值只能转换到更窄小的浮点表达式Rule 10.6(强制): 所有的 unsigned 类型都应该有后缀”U“Rule 11.1(强制) :指针不能转换为函数或者整型以外的其他类型Rule12.2(强制) :表达式的值应和标准允许的评估顺序一致例:X=bi + i+;不同的编译器给出的结
9、果不一样,bi是否先执行?应:x=bi;i+;比如:X=func(i+,i);Rule12.3(强制):sizeof 操作符不能用在包含边界作用(side effect) 的表达式上例:Int32_t=i;Int32_t=j;j=sizeof(i=1234);表达式并没有执行,只是得到表达式类型 int 的 sizeRule 12.4(强制) :逻辑操作符Rule13.1(强制) :赋值语句不能用在一个产生布尔值的表达式中例:If(x=y)!=0)更差:If (x=y)Rule13.3(强制): 浮点表达式不应该测试其是否相等或者不相等Rule13.4(强制):for 控制表达式中不要包含任何
10、浮点类型Rule13.6(强制): 数字变量作为 for 循环的循环计数不要在循环体内部被修改例:Flag=1;For(i=0;(iRule 14.1(强制): 不要有执行不到的代码例:Swich(event)Case www;do_wakeup();break;do_more();Rule 14.4(强制) :goto 语句不能使用Rule 14.5(强制) :continue 不能使用Rule 14.6(强制): 函数应在函数结束有一个出口Rule 14.7(强制) :witch,while,do .while,for 语句体应是一个混合语句(括号)Rule 14.10(强制): 所有 i
11、felse if 结构都应该由 else 结束Rule 15.3(强制) :switch 的最后应是 defaultRule 15.4(强制) :switch 表达式不能使用布尔表达式例:Switch(x=0) Rule 15.5(强制) :每一个 Switch 语句都应该有一个 case例:Switch(x)Uint8_t var; /* 违反*/Case 0:A=b;Rule16.2(强制): 函数不能直接或者间接的调用自己注:safe-related 系统不能用递归,超出堆栈空间很危险Rule16.8(强制) :non-void 类型函数的所有出口路径都应该有一个明确的 return语句
12、表达式Rule17.1(强制) :指针的数学运算只能用在指向数组的地址上Rule17.3(强制) :,=,Rule18.4(强制) 不要用 UnionRule19.1(建议) :#include 语句的前面只能有其他预处理指令和注释Rule19.2(建议) :#include 指令中的头文件名称不能包含非标准的字符Rule19.5(强制) :宏不能在函数体内定义Rule19.8(强制) :类函数宏调用时不能没有它的参数Rule20.1(强制) :标准库中的保留标识符,宏和函数不能定义,重定义,和undefinedRule20.4(强制) :动态内存分配不能使用注:不能使用:malloc,cal
13、loc,free,reallocRule20.9(强制) :输入输出库(stdio.h) 不能用在产生嵌入式系统中Rule20.12(强制) :时间处理函数 不能使用Rule 21.1(强制) :通过使用一下手段确保把运行时故障最小化: 静态分析工具/技术 动态分析工具/技术 编写明确的代码避免运行时错误“安全第一”的 C 语言编程规范作者:清华大学 陈萌萌 邵贝贝文章来源:单片机与嵌入式系统应用 2006-4-6 17:44:18 编者按: C 语言是开发嵌入式应用的主要工具,然而 C 语言并非是专门为嵌入式系统设计,相当多的嵌入式系统较一般计算机系统对软件安全性有更苛刻的要求。1998 年
14、,MISRA 指出,一些在 C 看来可以接受,却存在安全隐患的地方有 127 处之多。2004 年,MISRA 对 C 的限制增加到 141 条。嵌入式系统应用工程师借用计算机专家创建的 C 语言,使嵌入式系统应用得以飞速发展,而 MISRAC 是嵌入式系统应用工程师对 C 语言嵌入式应用做出的贡献。如今 MISRA C 已经被越来越多的企业接受,成为用于嵌入式系统的 C 语言标准,特别是对安全性要求极高的嵌入式系统,软件应符合 MISRA 标准。从本期开始,本刊将分 6 期,与读者共同学习 MISRAC。第一讲:“安全第一的 C 语言编程规范”,简述 MISRAC 的概况。第二讲:“跨越数据
15、类型的重重陷阱”,介绍规范的数据定义和操作方式,重点在隐式数据类型转换中的问题。第三讲:“指针、结构体、联合体的安全规范”,解析如何安全而高效地应用指针、结构体和联合体。第四讲:“防范表达式的失控”,剖析 MISRAC 中关于表达式、函数声明和定义等的不良使用习惯,最大限度地减小各类潜在错误。第五讲:“准确的程序流控制”,表述 C 语言中控制表达式和程序流控制的规范做法。第六讲:“构建安全的编译环境”,讲解与编译器相关的规范编写方式,避免来自编译器的隐患。C/C+语言无疑是当今嵌入式开发中最为常见的语言。早期的嵌入式程序大都是用汇编语言开发的,但人们很快就意识到汇编语言所带来的问题难移植、难复
16、用、难维护和可读性极差。很多程序会因为当初开发人员的离开而必须重新编写,许多程序员甚至连他们自己几个月前写成的代码都看不懂。C/C+语言恰恰可以解决这些问题。作为一种相对“低级”的高级语言,C/C+语言能够让嵌入式程序员更自由地控制底层硬件,同时享受高级语言带来的便利。对于 C 语言和 C+语言,很多的程序员会选择 C 语言,而避开庞大复杂的C+语言。这是很容易理解的C 语言写成的代码量比 C+语言的更小些,执行效率也更高。对于程序员来说,能工作的代码并不等于“好”的代码。“好”代码的指标很多,包括易读、易维护、易移植和可靠等。其中,可靠性对嵌入式系统非常重要,尤其是在那些对安全性要求很高的系
17、统中,如飞行器、汽车和工业控制中。这些系统的特点是:只要工作稍有偏差,就有可能造成重大损失或者人员伤亡。一个不容易出错的系统,除了要有很好的硬件设计(如电磁兼容性),还要有很健壮或者说“安全”的程序。然而,很少有程序员知道什么样的程序是安全的程序。很多程序只是表面上可以干活,还存在着大量的隐患。当然,这其中也有 C 语言自身的原因。因为 C 语言是一门难以掌握的语言,其灵活的编程方式和语法规则对于一个新手来说很可能会成为机关重重的陷阱。同时,C 语言的定义还并不完全,即使是国际通用的 C 语言标准,也还存在着很多未完全定义的地方。要求所有的嵌入式程序员都成为 C 语言专家,避开所有可能带来危险
18、的编程方式,是不现实的。最好的方法是有一个针对安全性的 C 语言编程规范,告诉程序员该如何做。1 MISRAC 规范1994 年,在英国成立了一个叫做汽车工业软件可靠性联合会(The Motor Industry Software Reliability Association,以下简称 MISRA)的组织。它是致力于协助汽车厂商开发安全可靠的软件的跨国协会,其成员包括:AB 汽车电子、罗孚汽车、宾利汽车、福特汽车、捷豹汽车、路虎公司、Lotus 公司、MIRA 公司、Ricardo 公司、TRW 汽车电子、利兹大学和福特 VISTEON 汽车系统公司。经过了四年的研究和准备,MISRA 于
19、1998 年发布了一个针对汽车工业软件安全性的 C 语言编程规范汽车专用软件的 C 语言编程指南(Guidelines for the Use of the C Language in Vehicle Based Software),共有 127 条规则,称为 MISRAC:1998。PageC 语言并不乏国际标准。国际标准化组织(International Organization of Standardization,简称 ISO)的“标准 C 语言”经历了从 C90、C96 到 C99的变动。但是,嵌入式程序员很难将 ISO 标准当作编写安全代码的规范。一是因为标准 C 语言并不是针对代
20、码安全的,也并不是专门为嵌入式应用设计的;二是因为“标准 C 语言”太庞大了,很难操作。MISRAC:1998 规范的产生恰恰弥补了这方面的空白。随着很多汽车厂商开始接受 MISRAC 编程规范,MISRAC:1998 也成为汽车工业中最为著名的有关安全性的 C 语言规范。2004 年,MISRA 出版了该规范的新版本MISRAC:2004。在新版本中,还将面向的对象由汽车工业扩大到所有的高安全性要求(Critical)系统。在 MISRAC:2004 中,共有强制规则 121 条,推荐规则 20 条,并删除了 15 条旧规则。任何符合 MISRAC:2004 编程规范的代码都应该严格的遵循
21、121 条强制规则的要求,并应该在条件允许的情况下尽可能符合 20 条推荐规则。MISRAC:2004 将其 141 条规则分为 21 个类别,每一条规则对应一条编程准则。详细情况如表 1 所列。表 1MISRAC:2004 规则分类最初,MISRAC:1998 编程规范的建立是为了增强汽车工业软件的安全性。可能造成汽车事故的原因有很多,如图 1 所示,设计和制造时埋下的隐患约占总数的 15%,其中也包括软件的设计和制造。MISRAC:1998 就是为了减小这部分隐患而制定的。MISRAC 编程规范的推出迎合了很多汽车厂商的需要,因为一旦厂商在程序设计上出现了问题,用来补救的费用将相当可观。1
22、999 年 7 月 22 日,通用汽车公司(General Motors)就曾经因为其软件设计上的一个问题,被迫召回350 万辆已经出厂的汽车,损失之大可想而知。MISRAC 规范不仅在汽车工业开始普及,也同时影响到了嵌入式开发的其他方向。嵌入式实时操作系统 C/OSII 的 2.52 版本虽然已经于 2000 年通过了美国航空管理局(FAA)的安全认证,但 2003 年作者就根据 MISRAC:1998 规范又对源码做了相应的修改,如将if (pevent-OSEventTbly if (pevent-OSEventTbly = 0) /* */ 发布了 2.62 的新版本,并宣称其源代码
23、99符合 MISRAC:1998 规范。一个程序能够符合 MISRAC 编程规范,不仅需要程序员按照规范编程,编译器也需要对所编译的代码进行规则检查。现在,很多编译器开发商都对 MISRAC规范有了支持,比如 IAR 的编译器就提供了对 MISRAC:1998 规范 127 条规则的检查功能。2 MISRAC 对安全性的理解MISRAC:2004 的专家们大都来自于软件工业或者汽车工业的知名公司,规范的制定不仅仅像过去一样局限于汽车工业的 C 语言编程,同时还涵盖了其他高安全性系统。图 1 汽车事故原因分布图 MISRAC:2004 认为 C 程序设计中存在的风险可能由 5 个方面造成:程序员
24、的失误、程序员对语言的误解、程序员对编译器的误解、编译器的错误和运行出错(runtime errors)。程序员的失误是司空见惯的。程序员是人,难免会犯错误。很多由程序员犯下的错误可以被编译器及时地纠正(如键入错误的变量名等),但也有很多会逃过编译器的检查。相信任何一个程序员都曾经犯过将“= =”误写成“=”的错误,编译器可能不会认为if(x=y)是一个程序员的失误。再举个例子,大家都知道+运算符。假如有下面的指令:i=3;printf(“%d”,+i);输出应该是多少?如果是:printf(“%d”,i+);呢?如果改成-i+呢?i+i 呢?i+i 呢?绝大多数程序员恐怕已经糊涂了。在 MISRAC:2004 中,会明确指出+或-运算符不得和其他运算符混合使用。C 语言非常灵活,它给了程序员非常大的自由。但事情有好有坏,自由越
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。