软件开发中的BUG案例
1 概述
众所周知,软件开发过程中BUG是难以避免的。但是一个训练有素的程序员却能将BUG的出现率尽可能的降低。本文档将BUG粗略地分为几个大类,以便于学习参考。
- 程序结构和处理逻辑类:包括程序的结构,算法的选择和实现等。
- 可移植性类:包括跨平台代码的移植、封装等。
- 可维护性类:包括诊断性代码、测试支持、注释、命名风格等。
- 其他问题:不好归类的BUG、实践技巧等。
2 程序结构和处理逻辑
2.1 ##
某Linux应用程序采用了DailyBuild,为了自动维护其构建版本号,我们将每日构建的版本号单独定义为:
#define BUILDNO?“0001”
需要引用该版本号的地方采用了预编译操作符“##”:
#define VERSION?“8.0.”##BUILDNO””
#define VERSION_STR “8.0.”##BUILDNO” Special Release for RedHat Linux 8.0”
这在GCC 3.3之前工作得很好,可是换成了 GCC 3.3.1 后,出现了错误:
foo.c:127:33: pasting ""8.0."" and "BUILDNO" does not give a valid preprocessing token
解决的办法很简单,就是将“##”去掉。结尾的空串””也是多余的。操作符“##”的用途主要是用于宏展开时将参数保留为字符串形式,例如:
#define __CONCAT(x, y)?x##y
__CONCAT(foo, bar)
2.2 变量初始化
某系统支持UNIX命令行风格的命令,例如:SHOW SETTINGS等。其语法分析代码中使用了一个全局字符串数组,用于记录某些特殊的语法片断。可是该变量不是每次语法分析启动前都初始化的,导致以下现象发生了:
某个命令执行第一次没有问题,但连续执行4次就会导致系统内部的内存检查模块报告异常。
因为问题很容易重现,系统内部的内存检查机制工作正常,很快定位到相关的代码:
char ParseString[1024];
if (ParseString == NULL)?/* 注1