The betray of compiler

来源:互联网 发布:matlab求矩阵方差 编辑:程序博客网 时间:2024/05/18 00:34

       如果在调试的过程中发现了一个隐蔽的或者激动人心的bug,或者找到了相应的解决方案,一定要及时记下来,否则日后就没有热情了,或者细节就既不清楚了。前几天我就发现了这样的一个bug。这个故事是将编译器和调试器的恩恩怨怨的。

      初,在IAR中写了一段程序,有若干语法错误,在编译器的指导之下一一改正,编译通过。于是看结果,结果总是不对。我以为是我写的函数有逻辑bug,于是开始调试。经过了很长时间的调试之后,将问题锁定在RouteNextHop这个函数中,其定义如下:

uint16 RouteNextHop(uint16 DesAdd)

{

……

for(i=0;i<MAXCHILDREN;i++)
{
NextHopAddr=GetShortAddr(NodeInfo.MyAddr,i);
if(DesAdd==NextHopAddr)
{
return NextHopAddr;
}
}

……

}

乍一看,没啥问题,于是后来我换了一种实现方式,后者就可以了:

uint16 RouteNextHop(uint16 DesAdd)

{

……

hDes=DesAdd>>12;
hLocal=NodeInfo.MyAddr>>12;
lDes=DesAdd&0x0fff;
lLocal=NodeInfo.MyAddr&0x0fff;
if((hDes-hLocal==1)&&(lDes/MAXCHILDREN==lLocal))
return DesAdd;

……

}

      本来觉得既然行了就不管了,但是本着求是的态度,我还是希望查出原因。前者即使传入和其中一个NextHopAddr相等的DesAdd,NextHopAddr也不会被返回。于是问题就被锁定在GetShortAddr这个函数上了。我一直以为是我的GetShortAddr的逻辑有问题,由于这个函数是在网络上跑的,用于通信,如果使用断点调试会让芯片的程序停止运行,这样整个网络的工作就会异常,这就是在这个项目里我不喜欢使用断点调试的原因。然而我把这个函数的实现拷贝到VC++6.0上面,运行没有问题。此事怪哉!为了找出这个问题的原因,我人为设置进入这个函数的条件,即一个节点一个节点地往网络里面进行添加,并且在函数调用之前加其他的约束条件,这样我能在我希望它进入函数的时候让它进入,并且不影响整个网络的工作。

      我开始断点调试,我发现我给GetShortAddr传入的i的值分明是0或者1,但是进入GetShortAddr这个函数之后,那个参数的值变成了3!这个调试工具出问题了?但是我试过好多次,都是这样的。这是什么原因?于是我觉得可能是这个函数的声明和定义不一致,这样传入的参数由于不够或者多了,导致引用的参数不正确。于是我观察了声明和定义,他们是一致的。何为其然也?我终于想到,我在写程序的时候就曾想过,如果一个函数定义在fun.c这个文件中,但是在ref.c中引用,但是没有包含相应的头文件,也没有使用extern进行声明,这样就会导致语法错误。当时的想法是这个不用担心,因为编译器是会报错的,但是编译已经通过,应该不是这个问题,但是我还是看了一下,真的没有使用extern声明,也没有包含,但是也没有报错!于是我增加了extern进行声明,就可以了。

      各位看官,当时我的心情你们能懂吗?我感觉编译器是值得信赖的,它会告诉你所有的错误。但是正是这么值得信赖的一个小家伙,竟然背叛了你,它窝藏了一个bug,害的我查了一整天!

原创粉丝点击