1、嵌入式软件可靠性设计 问题集锦目 录1、程序员理解错误 .21.1、英文标点被误写成中文标点; .21.2、+=与=+、-=与=-容易混 .21.3、程序员输入错误 .21.4、数组问题 .21.5、 switchcase 语句中的 break 关键字 .31.5、变量赋值 .31.6、指针的加减运算 .41.7、增量运算符+和减量运算符- .52、编译器语义检查 .62.1、数据类型问题 .62.2、误加标点符号 .62.3、编译器忽略掉多余的空格符和换行符 .62.4、数组越界。 .72.5、数组声明具有外部链接时大小应显式声明 .72.6、编译器检查不出数组越界 .82.7、编译器与 v
2、olatile 限定符 .92.8、 定义为 volatile 的变量的作用过程 .112.9、局部变量必须显式初始化 .113、不合理的优先级 .123.1、常规使用可能引起误会的运算符 .134、隐式转换和强制转换 .134.1、有符号和无符号 char 和 short 类型自动转换 .134.2、混合数据类型运算中会转换成较高级别数据类型 .144.3、赋值语句计算结果被转换成被赋予值的变量类型 .154.4、作为函数参数被传递时的数据类型转换 .154.5、 C 语言强制类型转换规则 .154.6、通用编程建议 .155、判错 .155.1、具有形参的函数,需判断传递来的实参是否合法。
3、 .165.2、仔细检查函数的返回值 .175.3、防止指针越界 .175.4、防止数组越界 .175.5、数学运算 .185.6、其它可能出现运行时错误的地方 .206、容错 .206.1、关键数据多区备份,取数据采用“表决法” .206.2、非易失性存储器的数据存储 .216.3、软件锁 .216.4、通信数据的检错 .216.5、开关量输入的检测、确认 .226.6、开关量输出 .226.7、初始化信息的保存与恢复 .226.8、陷阱 .226.9、 while 循环 .226.10、系统自检 .221、程序员理解错误1.1、英文标点被误写成中文标点;比较运算符=误写成赋值运算符=,代码
4、 if(x=5) 本意是比较变量 x 是否等于常量 5,但是误将=写成了=,if 语句恒为真。如果在逻辑判断表达式中出现赋值运算符,现在的大多数编译器会给出警告信息。并非所有程序员都会注意到这类警告,因此有经验的程序员使用下面的代码来避免此类错误:if(5=x) 将常量放在变量 x 的左边,即使程序员误将=写成了=,编译器会产生一个任谁也不能无视的语法错误信息:不可给常量赋值!1.2、+=与=+、-=与=-容易混复合运算符会给程序带来隐含 Bug,如下所示代码:tmp=+1;该代码本意是想表达 tmp=tmp+1,但是将复合赋值运算符+=误写成=+:将正整数常量1 赋值给变量 tmp。编译器会
5、欣然接受这类代码,连警告都不会产生。-=与=-同理。类似的逻辑与 break; case THING2: if(x=STUFF) do_first_stuff(); if(y=OTHER_STUFF) break; do_later_stuff(); /*代码的意图是跳转到这里 */ initialize_modes_pointer(); break; default: processing(); /* 但事实上跳到了这里。*/ use_modes_pointer();/*致使 modes_pointer 未初始化*/ 1.5、变量赋值int a=34int b=034变量 a 和 b 相等吗
6、?No。以0x为前缀的 16 进制常量,10 进制常量不需要前缀,数字0为前缀的 8进制。误用 8 进制的例子,最后一个数组元素赋值错误:1. a0=106; /*十进制数 106*/ 2. a1=112; /*十进制数 112*/ 3. a2=052; /*实际为十进制数 42,本意为十进制 52*/ 1.6、指针的加减运算下面的代码运行在 32 位 ARM 架构上,执行后,a 和 p 的值?int a=1; int *p=(int*)0x00001000; a=a+1; p=p+1; a=2,但是 p 的结果是 0x00001004。指针 p 加 1 后,p 的值增加了 4。原因是指针做加
7、减运算时是以指针的数据类型为单位。p+1 实际上是 p+1*sizeof(int)。不理解这一点,在使用指针直接操作数据时极易犯错。比如下面对连续 RAM 初始化零操作代码:unsigned int *pRAMaddr; /定义地址指针变量 for(pRAMaddr=StartAddr;pRAMaddr=0;i-) 无符号 char 类型,范围为 0255,所以无符号 char 类型变量 i 永远小于 256(第一个for 循环无限执行),永远大于等于 0(第二个 for 循环无限执行)。2.2、误加标点符号1. if(ab); /这里误加了一个分号 2. a=b; /这句代码一直被执行 2.
8、3、编译器忽略掉多余的空格符和换行符1. if(n=3 时,表达式 logrec.data=x0;就不会被执行,给程序埋下了隐患。2.4、数组越界。代码在硬件上运行,一段时间后 LCD 显示屏上的一个数字不正常的被改变。经过一段时间的调试,问题被定位到下面的一段代码中:int SensorData30; .for(i=30;i0;i-) SensorDatai=.; . 这里声明了拥有 30 个元素的数组,不幸的是 for 循环代码中误用了本不存在的数组元素 SensorData30。按照代码改变了数组元素 SensorData30所在位置的值, SensorData30所在的位置原本是一个 LCD 显示变量。很多编译器会对上述代码产生警告:赋值超出数组界限。但并非所有程序员都对编译器警告保持足够敏感,而且编译器也并不能检查出数组越界的所有情况。2.5、数组声明具有外部链接时大小应显式声明模块 A 中定义数组:int SensorData30;在模块 B 中引用该数组,但由于你引用代码并不规范,这里没有显式声明数组大小,但编译器也允许这么做: