arongnet 阅读(793) 评论(6)

对于一个程序员而言,学习一种语言和一种算法是非常容易的(不包括那些上学花很多时间玩,上班说学习没时间的人)。但是,任何程序都可能是有瑕疵的,尤其有过团队协作编程经验的人,对这个感触尤为深刻。

在我前面的述及调试的文章里,我侧重于VC集成环境中的一些设置信息和调试所需要的一些基本技巧。但是,仅仅知道这些是不够的。一个成功的调试的开端是编程中的准备。

分离错误

很多程序员喜欢写下面这样的式子:

   CLeftView* pView =
     ((CFrameWnd*)AfxGetApp()->m_pMainWnd)->m_wndSplitterWnd.GetPane(0,0);

如果一切顺利,这样的式子当然是没什么问题。但是作为一个程序员,你应该时刻记得任何一个调用在某些特殊的情况下都可能失败,一旦上面某个式子失败,那么整个级联式就会出问题,而你很难弄清楚到底哪儿出错了。这样的式子的结果往往是:省了2分钟编码的时间,多了几星期的调试时间。

对于上面的式子,应该尽可能的把式子分解成独立的函数调用,这样我们可以随时确定是哪个函数调用出问题,进口缩小需要检查的范围。

检查返回值

检查返回值对于许多编程者来说似乎是一个很麻烦的事情。但是如果你能在每个可能出错的函数调用处都检查返回值,就可以立刻知道出错的函数。

有些人已经意识到检查返回值的重要性,但是要记住,只检查函数是否失败是不够的,我们需要知道函数失败的确切原因。例如下面的代码:

if(connect(sock, (const sockaddr*)&addr,sizeof(addr)) == SOCKET_ERROR)
{
         AfxMessageBox("connect failed");
}

尽管这里已经检查了返回值,实际上没有多少帮助。正如很多在vckbase上提问的人一样,大概这时候只能喊“为什么连接失败啊?”。这种情况下,其实只能猜测失败的原因,即使高手,也无法准确说出失败的原因。

增加诊断信息

在知道错误的情况下,应该尽可能的告诉测试、使用者更多的信息,这样才能了解导致失败的原因。如果程序员能提供如下错误信息,对于诊断错误是非常有帮助的:

  1. 出错的文件:我们可以借助宏THIS_FILE和__FILE__。注意THIS_FILE是在cpp文件手工定义的,而__FILE__是编译器定义的。当记录错误的函数定义在.h中时,有时候用THIS_FILE更好,因为他能说明在哪个cpp中调用并导致失败的。
  2. 出错的行:我们可以借助宏__LINE__
  3. 出错的函数:如果设计的好,有以上两项已经足够。当然我们可以直接打印出出错的函数或者表达式,这样在大堆代码中搜索(尤其是不支持go to line的编辑器中)还是很有用的。大家可以参见我的文章中的方式进行处理,也许是一个基本的开端。
  4. 出错的原因:出错的原因很多只能由程序自己给出。如果出错只会问别人,那么你永远不可能成为一个合格的程序设计人员。很多函数失败时都会设置errno。我们可以用GetLastError获得错误码,并通过FormatMessage打印出具体错误的文字描述。

终了

给初学者一个忠告:编程时麻烦10分钟,调试时省却数小时,要想省时间,还是要从代码的可重用性和可维护性上下功夫,而不是两个代码上节省。

评论列表
铅笔谬书
re: 调试之编程准备
不包括那些上学花很多时间玩,上班说学习没时间的人
倒,还念念不忘的!
freedk
re: 调试之编程准备
__FILE__ __LINE__ GetLastError strerror

一个都不能少~~~~~~~~
Diviner
re: 调试之编程准备
__FUNCTION__也不能少
小明
re: 调试之编程准备
说的蛮中肯的

发表评论
切换编辑模式