CAN/CANFD
CCP/UDS
Bootloader/OTA
ECU/VCU/FCU
Simulink/ECUCoder
Ethernet
Hardware
Download
上一篇
下一篇
MISRA C-2012中文版
一.MISRA C简介
二.具体规则
-1.标准C环境准则
-2.未使用的代码的处理
-3.注释
-4.字符集
-5.标识符
-6.类型
-7.常量
-8.声明与定义
-9.初始化
-10.基本数据类型
-11.指针类型转换
-12.表达式
-13.副作用
-14.控制语句表达式
-15.控制流
-16.switch语句
-17.函数
-18.指针和数组
-19.重叠存储
-20.预处理指令
-21.标准库
-22.资源
回到顶部
MISRA C-2012中文版
一.MISRA C简介
二.具体规则
-1.标准C环境准则
-2.未使用的代码的处理
-3.注释
-4.字符集
-5.标识符
-6.类型
-7.常量
-8.声明与定义
-9.初始化
-10.基本数据类型
-11.指针类型转换
-12.表达式
-13.副作用
-14.控制语句表达式
-15.控制流
-16.switch语句
-17.函数
-18.指针和数组
-19.重叠存储
-20.预处理指令
-21.标准库
-22.资源
回到顶部
# MISRA C-2012中文版 ## 一.MISRA C简介
MISRA C是由汽车产业软件可靠性协会(MISRA)提出的C语言开发标准。其目的是在增进嵌入式系统的安全性及可移植性。 MISRA C一开始主要是针对汽车产业,不过其它产业也逐渐开始使用MISRA C:包括航天、电信、国防、医疗设备、铁路等领域中都已有厂商使用MISRA C。 MISRA C的第一版是在1998年发行,一般称为MISRA-C:1998。在2004年时发行了第二版的MISRA C,称作MISRA-C:2004。2012年发布第三版,为当前最新有效的C语言规范版本,称为MISRA-C:2012。 MISRA C不能100%保证程序不出问题,但是能尽可能的预防,总结一下,基本上使用MISRA C具有以下五个维度的优势: 1. 提升可靠性 2. 提升可读性 3. 提升可移植性 4. 提升可维护性 5. 提升安全性 ## 二.具体规则
### 1.标准C环境准则
1. 必需。程序应不包含违反标准C语法和限制的内容,也不应超出执行的转换限制。程序只能使用C语言及其库中所选标准版本中指定的特性,比如目前比较流行的C语言版本是C99,如果项目中使用的编译器只支持到C99的话就不可使用C11的特性。 2. 建议。尽量不使用语言扩展。即不要用编程语言扩展属性,否则会降低程序的可移植性。 3. 必需。不得出现未定义或关键的未指定行为。所有未定义和关键的未指定行为请参考MISRA C:2012英文原版PDF文档附录H。 ### 2.未使用的代码的处理
1. 必需。不得包含执行不到的代码。 2. 必需。不得有死代码。任何可以删除掉但是不影响程序正常运行的代码都是无效代码,执行不到的代码与死代码是类似的,都属于无效代码,无效代码的存在可能会引起混乱。对于所有未使用的代码,必须删除。 3. 建议。不应包含被声明但未使用的类型。 4. 建议。不应包含未使用的标签声明。 5. 建议。不应包含未使用的宏定义。 6. 建议。函数中不应包含未使用的标记。 7. 建议。不应有未使用的函数参数。 ### 3.注释
1. 必需。不允许嵌套注释。 2. 必需。不允许在//注释中进行行拼接。 ### 4.字符集
1. 必需。八进制和十六进制转义字符序列应术语化(比如\001为八进制,\x01为十六进制,不可省略0)。 2. 建议。三字母词不应使用。 ### 5.标识符
1. 必需。外部标识符应区分开(通过命名区分)。 2. 必需。在同一范围和名称空间中声明的所需标识应不同。 3. 必需。声明于内部作用域的标识符不应隐藏外部作用域的标识符,即内部不应该与外部重名,否则会覆盖。 4. 必需。宏标识符应被区分。 5. 必需。标识符要区别于宏名。 6. 必需。typedef名应是独一无二的标识符。 7. 必需。标签名称应是独一无二的标识符。 8. 必需。定义有外部链接的对象或函数的标识符应是独一无二的。 9. 建议。定义有内部链接的对象或函数的标识符应是独一无二的。 ### 6.类型
1. 必需。位字段只能用一个合适的类型来声明。C90:无符号整型和有符号整型。C99:除上述两个以外还有布尔类型。 2. 必需。单个位命名的位字段不应是有符号类型。 在实际开发项目中,习惯上都使用int来声明位字段,可以同时满足C90与C99的要求。 ### 7.常量
1. 必需。不要使用八进制常量。 2. 必需。所有以无符号类型表示的整型常量都应加上'u'或'U'后缀。 3. 必需。小写字母'l'不应用于文字后缀。 4. 必需。除非对象类型是指向字符常量的指针,否则字符串不应赋给对象。 ### 8.声明与定义
1. 必需。类型应被显式声明。 2. 必需。函数应以原型形式命名参数。 3. 必需。所有对象和函数的声明需要使用完全相同的名字和参数。 4. 必需。当定义有外部链接的对象或函数时,兼容声明应是可见的。、 5. 必需。外部变量或函数应被在仅一个文件内被声明过。 6. 必需。有外部链接的标识符应有一个确切的外部定义。 7. 建议。若函数和对象仅被一个单元引用,最好不定义外部链接。 8. 必需。静态存储类说明符应在所有具有内部链接的对象和函数的声明中使用。 9. 建议。如果一个对象的标识符仅在一个函数内出现,该对象应被定义在块范围内。 10. 必需。内联函数定义时应用静态存储类声明。 11. 建议。当有外部链接的数组被定义,应显式指定其大小。 12. 必需。枚举列表内的枚举值应独一无二。 13. 建议。指针最好指向一个const类型的变量。 14. 必需。不得使用restrict限定词。 ### 9.初始化
1. 强制。自动变量在使用前应该被赋值。 2. 必需。结构体和和共用体的初始化应在大括号内完成。 3. 必需。数组不应被部分初始化。 4. 必需。一个对象的元素不应被多次初始化。 5. 必需。使用指定的初始化器初始化数组对象时,应明确指定数组的大小。 ### 10.基本数据类型
1. 必需。操作数不应是不合适的数据类型。 2. 必需。对于字符类型的表达式字符之间不应使用加减法。 3. 必需。不应将表达式的值赋给不同类型或更窄的基本类型。 4. 必需。一个算术运算符的两个操作数应是相同类型。 5. 建议。表达式的值不应被转换成一个不合适的类型。 6. 必需。复合表达式的值不应赋给一个有更宽基本类型的对象。 7. 必需。若复合表达式参与算术运算,那么另一个操作数不应是更宽的基本类型。 8. 必需。复合表达式的值不应被转换为不同的基本类型分类或更宽的基本类型。 ### 11.指针类型转换
1. 必需。不应在函数指针和其他类型间进行转换。例外:空指针可被转换为函数指针。函数指针可被转换为void类型。 2. 必需。不应在指向不完整类型的指针和任何其他类型的指针之间进行所需的转换。 3. 必需。不同类型指针间不应转换。 4. 建议。不应将指针转换为整形变量。 5. 建议。不应直接将void类型指针转换为指向对象的指针。 6. 必需。不应在指向void的指针和数值类型之间执行强制转换。 7. 必需。不应在指向对象的指针和非整数算术类型之间执行强制转换。 8. 必需。强制转换不应从指针指向的类型中删除任何 const 或 volatile 限定。 9. 必需。宏NULL应是唯一允许的整数NULL指针常量形式。 ### 12.表达式
1. 建议。表达式中的运算符优先级应明确。 2. 必需。移位运算符的右手操作数应该小于左手操作数的基本类型的位宽。 3. 建议。不应使用逗号运算符。 4. 建议。常量表达式的计算不应导致无符号整数的溢出与回绕。 ### 13.副作用
1. 必需。初始化列表不应包含持续副作用。 2. 必需。表达式的值和他的持续副作用应在允许的计算顺序下保持相同。 3. 建议。包含自增或自减的完整表达式应无其他除自增自减外的潜在副作用。 4. 建议。不应使用赋值运算的结果。 5. 必需。逻辑与和逻辑或的右手操作数不应包含持续副作用。 6. 强制。sizeof运算符的操作数不应包含任何有潜在副作用的表达式。 ### 14.控制语句表达式
1. 必需。循环计数器不应有浮点型数据。 2. 必需。for循环应完整。 3. 必需。控制语句不应一成不变。 4. 必需。if语句和迭代表达式应具有布尔类型。 ### 15.控制流
1. 建议。不应该使用goto语句。 2. 必需。goto语句应跳跃至同一函数后定义的标签语句。 3. 必需。被goto语句引用的任何标志都应在同一块中或任何包含goto语句的块中声明。 4. 建议。不应有多个break或goto语句来结束迭代语句。 5. 建议。一个函数在其结尾应该有单一的退出点,即一个函数最多有一个return语句。 6. 必需。迭代语句和选择语句的主体应是复合语句。 7. 必需。if ...elseif...语句应由一个else语句结束。 ### 16.switch语句
1. 必需。所有switch语句都要是完整的。 2. 必需。仅当最紧密封闭的复合语句作为switch语句的主体时,才使用switch标签。 3. 必需。每个switch分支都要有一个break语句。 4. 必需。每个switch语句都要有一个default标签。 5. 必需。default标签应出现在switch语句的第一个或最后一个标签处。 6. 必需。每个switch语句都要至少包含两个分支。 7. 必需。switch表达式不应有布尔类型。 ### 17.函数
1. 必需。不得使用头文件
内的功能。 2. 必需。函数不能调用自身,不管是直接或者间接的,即不允许递归调用。 3. 必需。函数应被明确定义。 4. 必需。所有函数退出位置都应有相应的返回语句,除了返回值为void类型的函数。 5. 建议。函数参数中若有数组,在调用函数的时候数组大小应与定义时的数组大小相同。 6. 强制。定义数组时不应在[]中包含static修饰的变量。 7. 必需。非空返回值的函数的返回值应当被使用。 8. 建议。函数参数不得被修改。 ### 18.指针和数组
1. 必需。数组的索引应该是指针数学运算中唯一允许的方式。 2. 必需。只有基地址相同的数组元素的指针间才可以相减。 3. 必需。除非指针指向同一个对象,否则不应使用关系运算符进行比较。 4. 建议。不要使用+、+=和-=操作符来应用于指针类型表达式。 5. 建议。不要定义两级以上的指针。 6. 必需。具有自动存储功能的对象的地址不得复制到第一个对象停止存在后仍然存在的另一个对象。 7. 必需。数组定义时必需指定大小。 8. 必需。变长数组不得使用。 ### 19.重叠存储
1. 强制。不得将对象分配或复制到重叠对象。 2. 建议。尽量不使用union关键字。 ### 20.预处理指令
1. 建议。#include指令前应只存在预处理器指令或注释。 2. 必需。头文件名中不应包含‘,’和注释字符。 3. 必需。#include后应跟随
或“filename”。 4. 必需。宏名不得与关键字冲突。 5. 建议。不要使用#undef。 6. 必需。宏的参数中不应出现类似预处理指令的符号。 7. 必需。由宏参数扩展产生的表达式应用括号括起来。 8. 必需。#if或#elif预处理指令的控制表达式应赋值为0或1。 9. 必需。#if或#elif中控制表达式使用的标识符在赋值前应被#define。 10. 建议。#和##预处理器操作符不应使用。 11. 必需。宏参数在紧随#后后续不得有##紧跟该参数。 12. 必需。用作 # 或 ## 运算符的操作数的宏参数,其本身需要进一步宏替换,只能用作这些运算符的操作数。 13. 必需。以#开头的一行应是有效的预处理指令。 14. 必需。所有的#else、#elif和#endif预处理指令应该同与他们相关的#if或者#ifdef指令放在相同的文件中。 ### 21.标准库
1. 必需。#define和#undef不得用于保留标识符或保留宏的名字。 2. 必需。不得定义保留的标识符或宏名。 3. 必需。不得使用
的allocation和deallocation函数。 4. 必需。不得使用标准头文件
。 5. 必需。不得使用标准头文件
。 6. 必需。标准库中的输入输出函数不应使用。 7. 必需。不得使用
的atof,atoi,atoll函数。 8. 必需。不得使用
的abort,exit,getenv和system函数。 9. 必需。不得使用
的bsearch函数。 10. 必需。不得使用标准库中的时间和日期函数。 11. 必需。不得使用标准头文件
。 12. 建议。尽量不使用
中的异常处理功能。 ### 22.资源
1. 必需。用标准库函数动态获得的资源应显式释放。 2. 强制。只有通过标准库函数分配的内存块才需要被释放。 3. 必需。同一文件不得在同时在不同流中读写。 4. 强制。不得尝试在以只读形式打开的流中写入数据。 5. 强制。指向文件对象的指针不应被引用。 6. 强制。在相关流关闭后文件指针的值不得再使用。