从毕业后参加工作开始,断断续续从事过软件开发、嵌入式开发已经20多年了。记得哪个前辈说过,只要是人编写的代码,就一定会产生BUG。也许有大牛可以打破这个魔咒,但我肯定不行。这些年来编写过的代码中,有各种各样的BUG。有业务逻辑上的,也有纯粹代码上的。大概是在2000年的时候,给一家日本企业做项目,把原来VB6上的代码转换为Java代码,基本上你只要熟悉两种语言的函数功能,转变过程基本上就不会出问题。这里说的基本上,是指的函数语句转换级别的,事实上还会有处理逻辑上的,比如某个函数实现的功能,是要具体考虑处理过程的细节的,比如最明显的是:在VB6中数组元素的下标是从1开始的,而Java的数组下标是从0开始,这样在后续处理中如果不分析处理过程所要完成的任务,转换结果就很可能出现错误。另外就是在数据类型以及集合类型上两者的不同地方也挺多的。
在嵌入式开发中,因为理解不到位,也犯过非常低级别的错误。记得是刚毕业三年的时候,因为业务需要,开发51单片机应用。那个时候用的是汇编语言,代码会写的很长。在完成了整体功能后,感觉代码没有模块化,导致阅读性不好,所以就着手改造成模块化,根据功能弄成子程序调用方式的。结果改造完成后,程序运行就不正常了。仔细分析改造结果,感觉功能、逻辑上没有任何问题。为此浪费了将近半个小时。最后对照着两组代码,最后终于发现了问题。在51单片机的处理程序中,0000H地址处通常设置为一个LJMP指令,跳转到主程序的入口处。在主程序中,一定要先给堆栈寄存器分配一个内存地址。这个分配处理一定要在启用中断以及调用子程序之前,否则在未分配堆栈地址的情况下,堆栈寄存器里装的是一个随机数,不定是什么值。这时如果发生中断以及调用子程序,会导致的入栈、出栈处理出现不可预知的错误,从而导致程序跑飞。
事实上,这些年遇到的坑挺多的,但上面两个至今依旧记忆犹新。
在嵌入式开发中经常还能遇见的坑,就是不同厂家同一个型号一致、功能一致的芯片,由于工作参数不同,导致系统运行不正常的。还有就是在使用循环变量时,由于定义的类型错误,导致程序陷入死循环的。比如以下程序:
unsigned char i=0;
for (i=0; i<512; i++) {
...
}
unsigned char类型的值的范围是0 - 255,而后面的for语句判断的界限值超过了255,结果会导致i在值变成255后,再加1,不会变成256,而是变成了0,于是下一次循环又从0开始了,导致for循环会一直被执行下去,进入死循环。
在工作的这些年了,遇到的BUG越多,会越觉得作为程序员的不易。编程本身不仅仅是为了完成业务机能上的处理,在测写代码的同时,还要考虑太多与业务处理无关的东西,这些东西往往需要经验积累,没有一颗沉静的心,编程这件事儿,还真不太好干。