1
MISRA C 2012 规范
前言
本文档翻译 MISRA C 2012 版的规则,以及作为代码编辑者对规则的理解和建议。
本文档可作为 MISRA C 2012 原始文档(英文文档)的补充,辅助理解 MISRA C 规则。
译者补充的描述,建议内容会以红色标注,辅助理解的补充内容则以蓝色标注。
刘常浩
2020.06.05
2
名词解释
Guideline
MISRA C 规范第 7 章、第 8 章中条目的统称,本想翻译为“规则”,但在第 6 章中对其做了分类,分为
了“指令”和“规则”,故不可行。其直译可以为“指导方针”、“指南”、“准则”等,这份译档中,
取“准则”作为译名,不一定准确。
声明(declare)和定义(define)
声明一个变量只是将变量名标识符的有关信息告诉编译器,使编译器“认识”该标识符,但声明不一
定引起内存的分配。而定义变量意味着给变量分配内存空间,用于存放对应类型的数据,变量名就是对相
应的内存单元的命名。在 C/C++程序中,大多数情况下变量声明也就是变量定义,声明变量的同时也就完成
了变量的定义,只有声明外部变量时例外。函数类似,声明只是告诉编译器有这个名称、类型的函数,而
定义则是函数的真实实现。
连接/链接(linkage)
分为三类,外部连接(链接)(external linkage)、内部连接(链接)(internal linkage)和无连接(链
接)(no linkage)。具体描述可参阅《程序员的自我修养》一书,这里仅描述它们的特征。
外部连接(链接)(external linkage):对于变量,即无“static”修饰的全局可访问的变量;对于函
数,即无“static”修饰的全局可调用的函数。它们即使没有在头文件中用“extern”做外部声明,仍然
被识别为外部连接(链接)(external linkage)。
内部连接(链接)(internal linkage):即由“static”修饰的全局变量和函数,它们尽可在所在文件
内访问和调用,无法被全局访问/调用。
无连接(链接)(no linkage):即函数内部变量。所有函数都是有连接(链接,linkage)的。内部变量包
含临时变量和静态变量两种,它们的共同特征是均无法在本函数外被访问。
在下面的描述中,将不直接描述连接/链接,而已以全局,局部为描述,以便于理解。
对象(object)
本规范的编制,具有普适性,故会出现如“对象”、“类”这些标准 C 中不提及的概念,对象在 C 语
言中的直接对应是变量。当前对象不仅仅是变量,但本译文仅限考虑标准 C(准确的说是嵌入式 C),故不过
多描述,我们将其当成“变量”理解即可。
3
1 愿景(The vision)
MISRA C 指南定义了 C 语言的子集,以删除或减少犯错的机会。此 C 语言子集被许多用于开发与安全相
关的软件的标准要求或建议使用,并且它也可以用于开发具有高完整性或高可靠性要求的任何应用程序。
除了定义此子集外,这些 MISRA C 指南还提供了:
◇ 为正在开发 C 计划的人准备的教育材料;
◇ 工具开发人员参考资料。
以前的 MISRA C 版本是基于 1990 年的 ISO C 定义的。由于现在 1999 年的 ISO 定义已在不同程度上被
嵌入式实现所采用,人们认为发布 MISRA C 的新版本的时机已经成熟。 它认可了 1999 年的 ISO 定义。
上一版中提供的指南的各个方面均已进行了全面审查,并在适当时进行了改进。 此第三版还结合了根
据早期版本的指南用户提供的反馈而创建的材料。
第三版的主要变化是将第二版的基础类型概念发展为基本类型。 使用新的基本类型概念,有可能开发
出一套准则来为 C 语言带来更强的键入性。
第三版 MISRA C 的愿景是:
◇ 采用 1999 年的 C 语言 ISO 定义,同时保留对 1990 年的较早定义的支持;
◇ 更正第二版中的任何已知问题;
◇ 添加有充分理由的新准则;
◇ 改进现有准则的规范和理由;
◇ 删除任何理由不足的准则;
◇ 增加静态分析工具可以处理的准则数量;
◇ 提供有关准则对自动生成代码的适用性的指南。
4
2 MISRA C 的背景(Background to MISRA C)
2.1 C 语言的普及
C 编程语言之所以受欢迎是因为:
◇ C 编译器可用于许多处理器;
◇ C 程序可以编译为高效的机器代码;
◇ 它由国际标准定义;
◇ 它提供了直接或通过语言扩展来访问目标处理器的输入/输出功能的机制;
◇ 在关键系统中使用 C 有相当丰富的经验;
◇ 静态分析和测试工具广泛支持它。
2.2 C 语言的缺陷
尽管非常流行,但 C 语言具有一些缺点,以下各节将对此进行讨论。
2.2.1 语言的定义
ISO C 语言标准并未完全指定语言,而是将某些方面置于实现的控制之下。这是有意为之,部分原因是
希望兼容广泛不同的目标处理器的许多现有实现。
因此,在 C 语言的某些部分:
◇ 行为是未定义的;
◇ 行为是未指定的;
◇ 一个实现可以自由选择自己的行为,前提是它被记录在案。
依赖未定义或未指定行为的程序不一定能保证以可预测的方式运行。
过度依赖于实现定义的行为的程序可能很难移植到其他目标。如果无法配置分析器进行处理,则实现
定义的行为的存在也可能会妨碍静态分析。
2.2.2 语言的滥用
C 程序可以结构化和易于理解的方式进行布局,同时,C 也让程序员编写出难以理解的晦涩代码变得非
5
常容易。
C 的操作规范(的过分灵活)使得程序错误很难被编译器检测到。例如,以下两个代码片段都是合法的,
因此编译器不可能分辨出是否已经错误的使用了其中一个代替了另一个:
if (a == b) /* 检测 a 和 b 是否相等 */
if (a = b) /* 将 b 的值赋给 a, 然后检测 a 是否非 0 */
2.2.3 语言的误会(代码的误读)
C 语言的某些部分经常被程序员误解。例如,C 语言比其他某些语言拥有更多的运算符,因此具有大量
不同的运算符优先级,而其中有些并不直观。
C 提供的类型规则也会使熟悉强类型语言的程序员感到困惑。例如,操作数可以被“提升”为更宽的类
型,这意味着从操作中得出的类型不必与操作数相同。
2.2.4 运行时错误检查
C 程序可以被编译为小型高效的机器代码,但其代价是,运行时检查的程度非常有限。 C 程序通常不
对常见问题提供运行时检查,例如算术异常(例如零除),溢出,指针有效性或数组绑定错误。C 的哲学是程
序员负责显式地进行此类检查。
- 1
- 2
前往页