九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

Debug思考模式(1)—关注更改

Debug思考模式(1)—关注更改

程序员就像诗人,他的工作几乎全是纯思考弗里德里克·布鲁克斯

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

假如设计有模式,分析有模式,那么,程序员最希望有的自然是Debug的模式了。。。真希望有人已经总结出来了,以节省我们曾经浪费的大量时间。。。。可惜。。呵呵,好像没有看到,我碰到一些问题,顺面总结一下方法吧,当方法重复的被使用,那么也就成为一种Debug思考模式了。

 

前段时间为公司的TCP网络模块添加加密的功能,当时用的加密算法是从网上找的。。。为了安全,就不透露具体的算法了,算法的加密解密函数都写的很简单,就两个指针参数,由于仅仅是简单的算法实现,主要用于描述算法,没有配套的使用文档,也没有示例代码,一番折腾,调试很久,总算明白了2个参数的作用,不就一个传入需要加密解密的数值,一个传入自定义的key嘛。Debug通过后,直接编译了release版本给测试组测试,发现完全没有发挥作用。相当的郁闷,回来再调,还是正确的,但是编译成release版本后的确不行了。一般情况下碰到类似问题,不知道怎么的,都是第一反应没有初始化,查找外围代码老半天,并没有发现问题,由于Release下的调试功能比较弱,所以在算法加密解密函数调用前将内存中的值用日志的形式写了下来,发现加密本身就与debug下不一致,确定了问题改变的地点,肯定是加密算法的问题。仔细在release下调试加密算法,还好学会汇编,找到具体地点时release用汇编看就不那么吃力了,原来此算法的传入加密数值是64bit的,但是key却是用了128bit-_-!在没有任何说明注释的情况下,仅仅以两个指针作为参数传入,不自己调试根本没有办法发现。。。。。唉。。。碰巧Debug能对,在于MS为所有的Debug未初始化变量赋值0xcc。。。也就是在Debug下,我的key指针传入实际相当于是以我自己的key加上两个连续的0xcc,无论加密解密的key都还是一样的,所以一切正常,当release时,越界访问的值属于随机状态,key不一致了,加密解密自然也就不肯能对了。。。。。

首先还是的说一点,好的接口是容易用对的,坏的接口设计(比如这种)是容易用错的。这是《Effective C++》一书中讲过的,但是看来还是很多人没有真正理解,我就是受害者之一。。。。到了这里,可能会有人批评我,说假如我具体的了解了算法和看清楚了算法的实现就不会出这样的错误了,但是我想说的是,好的接口给人使用,就是让人可以不了解实现的,甚至接口和实现都可以分离,使用接口的人根本就需不要关心实现,这样才能更加关注于自己需要关注的东西。何况,工作嘛,哪能真的用什么就理解透了才去做啊。。。。。。

我这里想说的是,我犯的最大的错误在于出现问题时,没有很快的定位到错误所在的地方,事实上TCP网络模块公司一直在使用,我仅仅添加了加密模块,然后出现问题,那么首先可以想到的自然是加密模块的问题,但是由于我平时对公司的TCP网络模块没有太深入的了解,仅仅是平时调试的时候偶尔跟进去看看,所以对其还有怀疑,然后出现错误,特别是这种debug没有错误,release错误时,一下子没有了方向,开始漫无目的的乱怀疑,其实根本没有必要,一开始就应该定位到错误所在。

这就是总监最后批评我没有使用排除法的地方,此处我应该将原来正确的代码排除掉。

这是我想提出的一种Debug思考模式:

假如在更改此模块之前其他模块都能正常工作,首先关注于这次更改的模块。

 

这种Debug模式其实真的能深入到思想中,其实作用很大,但是需要注意一些特殊的例子。比如有一次,我为公司的世界地图服务器添加GM模块,此时由于公司内网测试使用的GM指令与此非常类似,于是我主要通过此GM指令系统来搭建新的模块,一切都非常顺利,由于新模块建立在旧模块上,代码的编写速度也是非常快,但是到了最后,又出现了问题,程序一运行就崩溃。。。。这时又另外一个问题,加重了问题的严重性,我从程序一开始的地方到崩溃的地方下了很多断点,但是断点竟然都断不上,一般出现这种情况,属于库和头文件不统一造成,但是此次的调试仅仅在本模块中,没有进入其他的库,所以让人很郁闷,后来发现的问题在于原有的GM指令根本不需要了解是谁在执行,所以没有使用IPlayer的指针,但是我由于需要详细记录GM的每个动作,所以必须使用到此指针,使用的时候由于是复制代码,所以完全复制原有代码过来,也没有思考,原来的使用就是通过OnMessge的参数WPARAM强转过来的,但是原来并没有使用,我在后面将其传入另一个函数并使用了此指针,导致程序崩溃,按总监的话来说,由于IPlayer属于多重继承而来,不能再像普通类型一样用强转了,以前的代码是老代码,所以使用的并不正确,但是由于没有使用,所以没有问题。也就是说,我栽倒在了一次原来的老代码强转错误上。这里,原有模块同样没有出现问题,而我的程序出现了。区别在于原有代码强转了指针却没有使用,我使用了其强转,接下来还是用了指针。

这里需要提出的是:

原有程序没有出现问题,不代表代码没有问题,关注于更改,就要关注每个细微的更改。

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

分类:  未分类 
标签: 

Posted By 九天雁翎 at 九天雁翎的博客 on 2009年04月20日

分享到:

前一篇: Python,Spam的有趣由来 后一篇: 序列化支持(4)—Boost的序列化库的强大之处