利用__FILE__, __LINE__, __FUNCTION__跟踪调试程序

转自:http://zhoulifa.bokee.com/3700951.html

 

作为一个Linux系统下的C程序员,你可能发现调试程序是个比较麻烦的工作,虽然已经有gdb,kgdb等专业的调试软件,但如果对这些软件运用不熟练是根本达不到调试程序找出bug的目的的。又或者你对gdb已经很熟了,但运行gdb开始调试后在哪里设置断点成了你头痛的问题?当然,你可以从程序开始就以单步运行step by step来调试程序,但这会耗去你很多时间。

如果你能很好地跟踪并记录程序的运行情况,那么一切将变得简单。下面我以一个实例说明我是如何操作的:

首先我有一个程序主体main,其代码如下:

//trace.c 开始///

/*********************************************************************

*filename: trace.c

*purpose: demonstrate how to trace program easily. We'll 

*         get every source filename, function-name, and the

*         current line number wrote into a stream. The stream

*         can be a file descriptor or stdout

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

 

#include "global.h"

#include "MyFuncOne.h"

#include "MyFuncTwo.h"

 

int x;

 

int main(int argc, char ** argv)

{

    x = 5;

    dump(stdout, "now: x=%d", x);

    MyFuncOne();

    MyFuncTwo();

    dump(stdout, "now: x=%d", x);

    return 0;

}

//trace.c 结束///

 

这个main里面引用了global.h,MyFuncOne.h,MyFuncTwo.h等,global.h里面是一个宏定义,定义了dump宏,其内容如下:

//global.h 开始///

#ifndef GLOBAL_H

    #define GLOBAL_H

    #include "dump.h"

 

/*********************************************************************

*filename: global.h

*purpose: dump function declare

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

    #ifdef DEBUG

        #define dump(fp, x...)  debug_print(fp, __FILE__, __LINE__, __FUNCTION__, ##x);

    #else 

        #define dump(fp, x...) 

    #endif

 

#endif

//global.h 结束///

global.h这里又引用了dump.h,其内容稍后再贴出来。

MyFuncOne.h和MyFuncTwo.h分别定义了两个函数MyFuncOne和MyFuncTwo,其内容如下:

//MyFuncOne.h 开始///

#ifndef MYFUNC_ONE_H

    #define MYFUNC_ONE_H

    #include "global.h"

/*********************************************************************

*filename: MyFuncOne.h

*purpose: MyFuncOne function declare

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

    void MyFuncOne();

#endif

//MyFuncOne.h 结束///

 

//MyFuncTwo.h 开始///

#ifndef MYFUNC_TWO_H

    #define MYFUNC_TWO_H

    #include "global.h"

/*********************************************************************

*filename: MyFuncTwo.h

*purpose: MyFuncTwo function declare

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

    void MyFuncTwo();

#endif

//MyFuncTwo.h 结束///

 

//MyFuncOne.c 开始///

#include "MyFuncOne.h"

 

extern int x;

/*********************************************************************

*filename: MyFuncOne.c

*purpose: MyFuncOne function instance

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

void MyFuncOne()

{

    x *= -2;

    dump(stdout, "MyFuncOne, now: x=%d", x);

}

//MyFuncOne.c 结束///

 

//MyFuncTwo.c 开始///

#include "MyFuncTwo.h"

 

extern int x;

/*********************************************************************

*filename: MyFuncTwo.h

*purpose: MyFuncOne function declare

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

void MyFuncTwo()

{

    x++;

    dump(stdout, "MyFuncTwo, now: x=%d", x);

}

//MyFuncTwo.c 结束///

 

现在该是时候说dump了,先看看其实现:

//dump.h 开始///

#ifndef DUMP_H

    #define DUMP_H

    #include <sys/param.h>

    #include <stdio.h>

    #include <stdarg.h>

    #include <time.h>

/*********************************************************************

*filename: dump.h

*purpose: debug_print function declare

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

    void debug_print(FILE * fp, const char * filename, const int line, const char * funcname, char *fmt, ...);

#endif

//dump.h 结束///

 

//dump.c 开始///

#include "dump.h"

 

/*********************************************************************

*filename: dump.c

*purpose: debug_print function instance

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

*date time:2005-11-30 00:30

*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途

*                         但请遵循GPL        

*********************************************************************/

void debug_print(FILE * fp, const char * filename, const int line, const char * funcname, char *fmt, ...)

{

    char buf[1024];

    time_t t;

    struct tm * now;

    va_list ap;

 

    time(&t);

    now = localtime(&t);

    va_start(ap, fmt);

    fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d -- %s(%d):%s DEBUG:@/"", now -> tm_year + 1900, now -> tm_mon + 1, now -> tm_mday, now -> tm_hour, now -> tm_min, now -> tm_sec, filename, line, funcname);

    vsprintf(buf, fmt, ap);

    fprintf(fp, "%s/"@/n", buf);

    va_end(ap);

}

//dump.c 结束///

 

大家一定注意到:这个程序和大家一般写的程序并无大的区别,除了__FILE__, __LINE__, __FUNCTION__等几个宏和dump宏,__FILE__, __LINE__, __FUNCTION__是编译的时候已经内置了的几个宏,用来表明当前程序运行到了哪个源文件的哪一行,同时表明当前在哪个函数里面。而我们定义一个dump宏就是用来把这些信息送到一个文件句柄去。比如你的日志文件。这样,在任何程序需要的地方都可以加上一句dump来把需要的调试信息记录下来。

比如编译上述程序:

gcc -DDEBUG trace.c dump.c MyFuncOne.c MyFuncTwo.c -o trace

然后运行程序可以得到如下结果:

2005-11-30 00:40:38 -- trace.c(22):main DEBUG:@"now: x=5"@

2005-11-30 00:40:38 -- MyFuncOne.c(15):MyFuncOne DEBUG:@"MyFuncOne, now: x=-10"@

2005-11-30 00:40:38 -- MyFuncTwo.c(15):MyFuncTwo DEBUG:@"MyFuncTwo, now: x=-9"@

2005-11-30 00:40:38 -- trace.c(25):main DEBUG:@"now: x=-9"@

第一行:显示在trace.c源文件的第22行处,即main函数内打印出:now: x=5;

第二行:显示在MyFuncOne.c源文件的第15行处,即MyFuncOne函数内打印出:MyFuncOne, now: x=-10;

第三行:显示在MyFuncTwo.c源文件的第15行处,即MyFuncTwo函数内打印出:MyFuncTwo, now: x=-9;

第四行:显示在trace.c源文件的第25行处,即main函数内打印出:now: x=-9;

 

如果程序加多点dump,则程序运行到了哪里出了问题就会一目了然了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值