没人能否认嵌入式应用正变得越来越普遍。但是,当系统越来越复杂,而我们赋予系统越来越多的责任的时候,我们将必须面对一些重要问题。其中最重要的问题是:我们如何才能确保嵌入式系统是安全可靠的? C 编程语言为用户提供了许多强大的功能,几乎与汇编语言一样强大。此外, C 语言还包含了一些在标准中未明确定义的区域和不用定义就能实现的条款。 用 C 来编写一个安全可靠的程序并不仅仅意味着该程序能完全按照编程者的预期来运行。它被移植到一个不同的环境下也需要正确运行。更重要的是,当其他人员阅读这些源代码时,它们必须像水晶一样清晰明了:一方面简化了不必要的猜测和诠释,另一方面当基于这些代码来做进一步开发时,能规避诱发新错误的风险。 汽车工业软件可靠性协会 (MISRA) 采取的措施是定义一套 C 编程语言的子集。如果在应用开发中仅使用这个子集,那么许多 C 编程语言中存在的缺陷就能被规避了。 这个子集名称为 "MISRA C" ,在一本名为“ Guides For The Use Of The C Language In Vehicle Based Software ”的手册中有具体定义。该指南共包括 127 条规则,分为“必选”和“建议”两类。 IAR Embedded Workbench 中几款产品(参见以下列表),内建了一个能检查绝大多数 MISRA C 规则的检查器,但是某些规则是无法被自动检测的。
如果在编写应用时忘了使用这些规则,以后再去修改应用以符合这些规范将非常困难。比如, MISRA C 第 118 条规则禁止使用动态分配内存,第 101 条规则规定禁止使用 指针运算 ,第 102 条规则表示不可以使用 超过两级的间接指针 。 另一方面,有几条规则是非常简单明了和成熟,即使你没有想过让你的应用做到 100% 的 MISRA C 兼容,如果能支持其中几条也至少能让应用更可靠一些。 在这篇文章里,我将推荐一些应该适用于所有项目的规则,即便你没想做到 100% 的 MISRA C 兼容。这些被挑选出来的规则通常是编译器不会去检查的。 在 IAR Embedded Workbench 中使用 MISRA C
在 IAR Embedded Workbench 中, MISRA C 的界面非常简单易用,你可以直接选择你所希望检查的规则,也可以在 "MISRA C" 标签下的 " 通用选项 " 部分的 "Options" 菜单列表中进行选择 。如果你使用命令行方式,你可以使用 --misrac 和 --misrac_verbose 命令选项。
大多数规则都由编译器自身来检查。然而,一些规则考察进入到整个应用才能检查,在这种情况下,链接器将执行检查。你可以分别通过列表文件和映射文件来察看被允许使用的规则和检查过的规则列表。请注意,有些规则是不能被自动检查到的。 规则 13 ( 建议使用 )
该条规则声明: 应用程序不应直接使用 char, int, float, 等基本数据类型,而应在特定的编译器中专门 typedef 自己定义特定长度的类型名称,并将 typedef 所定义的类型使 用到代码当中去。 原因是不同的编译器对基本类型会使用不同的底层表达方式。最常见的例子是 int 类型在某个编译器中被当作 16 位处理,而在另一个编译器中被当作 32 位处理。 根据个人经验,我一般会仔细选择定长类型的大小和符号。当我需要表示一个不可能为负数的东西时,我会选择使用 uint16_t ,而不是简单的用 int 表示。这样写代码的好处之一是代码很容易被读懂和理解,读者无须考虑该表达式为负数的情况。 1999 年版本的 C 标准包含的头文件 stdint.h 中,提供了 int8_t 和 uint32_t 形式的类型名称。 IAR Embedded Workbench 在 DLib 标准库中支持这一头文件。 规则 23 ( 建议使用 ): 具有文件范围作用域的所有对象声明都尽量定义成静态的。
正如你可能知道的那样,在应用程序中定义的静态变量和函数是无法被其他模块直接使用的。
该规则:
? 防止你无意间误用内部帮助函数和文件内部的变量
? 促使你认真设计新模块之间的接口
? 使程序接口更加清晰明了是一件很重要的事情,因为当时间久了之后,当初写代码的人未必能够继续留在那里维护应用程序。
使用 IAR Embedded Workbench 时,链接器会在整个应用范围内检测这条规则。
规则 33 ( 必需使用 ): 操作符 "&&" 和 "||" 的右侧表达式不得包含副作用
你可以用 C 语言写出如下代码:
if ((x == y) || (*p++ == z))
{
/* do something */
}
在这个例子中,仅当 || 操作符左边的表达式为假 —- 即 x 和 y 不相等时,才对右边的表达式进行求值(副作用就此产生)。在上述例子中,所谓的副作用就是增加了指针 p 的值。 虽然在标准中已经详细说明了该种行为,但在写代码的过程中还是容易犯下这种错误。即使写代码的人设法正确了解了这种行为,然而每个试图阅读代码或维护代码的人员也仍必须理解这些规则和程序员的意图。 以上代码可以按照另一种更为简洁明了的顺序重新编写:
int doSomething = 0;
if (x == y)
{
doSomething = 1;
}
else if (*p++ == z)
{
doSomething = 1;
}
if (doSomething)
{
/* do something */
}
规则 59 ( 必需使用 ): "if", "else if", "else", "while", "do ... while" 和 "for" 语句块必须用 {} 括起来
基本上来说,你必须整理好思路,不要随便的写出如下例中所示的 else 子句。
if (x == 0)
{
y = 10;
z = 0;
}
else
y = 20;
这条规则意在避免一个经典错误。在下面的例子中,另外增加了一行“ z = 1 ; ”。这行语句看上去是属于 else 子句的一部分,但其实并不是这样。事实上,这句语句紧接在全部的 if 语句块之后,这意味着该赋值将总是发生。
如果一开始就能够将 else 子句用大括号括起来,就不会产生这样的问题了。
if (x == 0)
{
y = 10;
z = 0;
}
else
y = 20;
z = 1;
产品支持
IAR 在以下的编译器产品中已经支持了 MISRA C 的兼容性检查。请注意只有在标准版本中(而不是评估版或代码限制版)该功能才能启用。
IAR Embedded Workbench for 78K0IAR Embedded Workbench for 8051
IAR Embedded Workbench for ARM
IAR Embedded Workbench for AVR
IAR Embedded Workbench for AVR32IAR Embedded Workbench for CR16CIAR Embedded Workbench for H8
IAR Embedded Workbench for M16C
IAR Embedded Workbench for M32C
IAR Embedded Workbench for MAXQ
IAR Embedded Workbench for MSP430
IAR Embedded Workbench for PIC18
IAR Embedded Workbench for R8CIAR Embedded Workbench for S12
IAR Embedded Workbench for V850
参考文档
《 Guides For The Use Of The C Language In Vehicle Based Software 》 — 汽车工业软件可靠性协会, 1998 年 4 月
集成 Misra C 的 IAR Embedded Workbench
IAR Embedded Workbench是一套用于编译和调试嵌入式系统应用程序的开发工具,支持汇编、C和C++语言。它提供完整的集成开发环境,包括编译器、汇编器、工程管理器、编辑器、编译链接工具和C-SPY调试器。 ? 广泛的芯片内核支持
- HCS12, M16C, M32C , R32C , V850, 78K, S08
- ARM, AVR32 , ColdFire
- 8051, AVR, PIC, SAM8, R8C , MSP430 等
? 编译产生的代码尺寸小、实时性强
IAR Systems 是全球第一家做 C 编译器的公司,先进的技术保证了编译器能产生可靠、紧凑的代码 ? 集成多种内核识别调试插件,包括 OSEK Run-Time Interface (ORTI)
通过它可以在调试器中显示 RTOS 内部数据结构窗口,从而了解每一个项目应用中运行任务的信息,每一个信号灯、互斥量、邮箱、队列、事件标志信息,以及等待上述内核对象的所有任务列表信息 集成 MISRA C 校验模块, 对代码进行可靠性检验 ? 支持多种仿真器,如 IAR J-Link/J-Trace、ROM-Monitor、MK-II、E8、Minicube2、P&E等;
状态机建模工具:设计阶段可靠性保证
visualSTATE 是一套精致、易用的开发工具, 包含图形设计器、测试工具包,代码生成器和文档生成器, 用于设计、测试和实现基于状态图设计的嵌入式应用。该款工具提供了先进的验证和测试模块,可以产生 100% 与 您系统设计一致的紧凑 C/C++ 代码 ,并 可以在任何 8 位、 16 位、 32 位架构上运行。此外,它革命性地与 IAR Embedded Workbench C/C++ 编译调试环境无缝集成 ,能够真正做到基于硬件去调试状态机模型,并以直观的图形方式反馈出各个设计层面的详细信息 ? 基于统一建模语言 (UML) 状态机理论的图形化模型设计;
? 对设计模型进行规范性验证,检查系统的逻辑一致性,鉴别出系统设计漏洞或错误;
? 设计过程的早期阶段,甚至在硬件设计尚未完成之前,就可以使用测试工具来确保应用能按照预想方式运行;
? 自动代码生成功能可以生成极为紧凑的 C/C++ 代码, 100% 与设计保持一致;
? 自动文档生成功能提供了详尽的信息;
? 与 IAR Embedded Workbench 无缝集成,提供多种微控制器和评估板的现成示例代码;
? 通过 CSPYLink 或 RealLink 对目标器件进行综合的图形化状态机调试;
? 支持多种硬件调试接口,例如 J-Link 、 通用 JTAG 仿真器 、 NEXUS 仿真器等
|