首页
杂志网
当前位置:首页>>软件开发>多联机软件开发中常见错误及MISRA C的应用>正文

多联机软件开发中常见错误及MISRA C的应用

来源:杂志发表网时间:2015-12-20 所属栏目:软件开发

  

  商用空调产品功能复杂,运行环境恶劣,尤其对于商用多联机来说,其控制软件可是说是电器类产品中最复杂的软件之一。 商用多联机控制软件不仅包含整个空调各个运行系统的控制逻辑而且还包含复杂的多机通讯,同时相同功能的代码需要在不同处理器之间移植。 因此,怎样提升多联机软件的可靠性、可移植性一直是多联机软件工程师研究的问题。

  1 MISRA C 编程规范

  MISRA C 是有汽车产业软件可靠性协会 (Motor IndustrySoftware Reliability Association)(MISRA) 提 出的 C 语 言开发标准。 其目的是在增进嵌入式系统的安全性以及可移植性 .MISRA C 一开始主要是针对汽车产业, 不过随着对 MISRA C认可度的提高,其他行业也开始逐渐使用 MISRA C. 目前大家熟悉的版本是 MISRA C : 2004 版。

  MISRA C:2004 包含 141 条规则,其中 121 条强制规则,20条建议规则。141 条规则分为 21 个类别,分别为:编程环境相关类规则;语言扩展类规则;文档类规则;字符集规则;标识符规则;类型规则;常量规则;声明与定义类规则;初始化规则;数值类型转换规则;指针类型转换规则;表达式规则;控制语句表达式规则;控制流规则;Switch 语句规则;函数类规则;指针和数组类规则;结构与联合体规则;预处理指令规则;标准库规则;运行时错误规则。

  2 多联机软件开发中常见错误以及 MISRA C 的应用

  多联机软件开发中常用的错误举例:

  2.1 条件遗漏

  开发过程中,程序员经常只对符合条件的处理,而遗漏了一些潜在的可能性,即在 if …else if…语句中经常忘记增加一个 else 语句,来处理剩余条件。 MISRA C 的第 14.10 规则要求所有的 if…else if…结构都必须以 else 句子结束,保证所有可能的条件都得到处理。

  2.2 表达式的计算顺序

  如 A = b+++c;语句, 程序员可能会依据标准 C 编译器的表达式计算顺序来得到预期的值,但因处理器的 C 编译器和标准 C 编译器并不一定相同,且不同编译器所编译的结果也不尽相同。 因此这类的表达式可能有不确定的结果,同时也增加了代码移植的难度, MISRA C 的 12.2 规则, 要求表达式在任何情况下求值顺序必须保持一致。 编程过程中尽可能的通过括号将表达式的计算顺序定好,保证唯一的计算顺序。

  2.3 数组越界

  多联机外机程序中经常定义一个数组用于存储所有内机的状态信息,通讯接收程序根据接收到的内机地址来定位对应内机在数组中的位置,如 if (InterDoorData[Address])语句中,Ad-dress 这个地址变量在特殊情况下可能超出数组定义的最大个数,因此数组访问就有可能越界。 MISRA C 的 21.1 规则,要求采用静态或动态分析工具,对数组越界的错误做出排查,可以及时发现数组访问越界的情况。

  2.4 代码移植过程中易出错

  相同功能的代码比如通讯功能的代码、内机自动寻址功能的代码,在不同品牌的处理器之间移植,经常出现难以发现的错误。 如变量类型定义、局部变量和全局变量重名导致的一些问题。 MISRA C 的一些规则能够有效的保证代码的可移植性,如局部变量不能和全局变量重名;作用于文件范围内的变量应当定义为 Static 型, 这样避免与其他文件中同名的全局变量冲突;局部变量在使用之前一定要赋值;移位操作符不应该在有符号变量上使用。

  2.5 由于联合体的使用产生的错误

  由于多联机控制芯片多使用 8 位的单片机,RAM 资源有效,为了有效利用资源,程序中一般会使用联合体来定义位变量。 多联机软件通讯部分联合体的应用常出现如下问题,如:用联合体定义了两个位变量 fRxOk 和 FlashLedOn.typedef union{unsigned char Byte;struct{unsigned RxOk : 1;unsigned FlashLedOn: 1;……}Bits;} FLAG3;extern FLAG3 mFlag3;#define fRxOk mFlag3.Bits.RxOk /* 正 确接收到一帧数据 */#define fFlashLedOn mFlag3.Bits.FlashLedOn……fFlashLedOn 在主循环中被清 0, fFlashLedOn = 0;以 Code-Warrior 编译器为例,其编译后的汇编代码为:

  LDA mFlag3 ……(1)AND #0FDH ……(2)STA mFlag3 ……(3)fRxOk 在通讯中断函数中被赋值。 fRxOk = 1;其编译后的汇编代码为:

  LDA mFlag3……(4)ORA #01H ……(5)STA mFlag3……(6)假设执行指令(1)之前,mFlag3= 0x02,当主循环(2)指令执行完毕瞬间,通讯接收中断产生,A =0x00 入栈,再执行(4)(5)(6)条指令后,mFlag3 = 0x03, 退出中断函数后, 堆栈中的 A =0x00 出栈,此时 A = 0x00;再执行指令(3),mFlag3=0x00. 而指令(4)(5)(6)原本的目的是将 mFlag3 的 第 0 位 置上 ,结果原本应该是 mFlag3 等于 0x01 而不是 0x00. 采用联合体定义位变量就有可能导致这样的问题。 鉴于单片机 RAM 有限, 可以对 MISRAC 的 18.4 规则进行部分遵循,即在所有中断函数中不允许用到联合体定义的数据,包括位变量和字符串定义。 只允许在主循环程序中使用联合体定义的数据。 如上例中,fRxOk 可以用一个单独定义的 unsigned char 型变量替代。

  3 结语

  软件开发过程中遵循 MISRA C 规范能够有效提高软件的安全性和可移植性,但在一定程度上也会增加编程难度。 由于MISRA C 规则比较多,难以人工逐一检查 ,许多 C 语言静态分析工具都支持 MISRA C 规则检查, 如 PCLINT 和 IAR 开发环境自带的规则检测工具等,开发过程中可以采用这类分析工具来提高工作效率。

  参考文献:

  [1]MISRA C :2004 版[2]CodeWarrior 集成开发环境使用手册[M].

点此咨询学术顾问 快人一步得到答案

SCI期刊问答

回到顶部