利用__FILE__, __LINE__, __FUNCTION__跟踪调试程序
作為一個(gè)Linux系統(tǒng)下的C程序員,你可能發(fā)現(xiàn)調(diào)試程序是個(gè)比較麻煩的工作,雖然已經(jīng)有g(shù)db,kgdb等專(zhuān)業(yè)的調(diào)試軟件,但如果對(duì)這些軟件運(yùn)用不熟練是根本達(dá)不到調(diào)試程序找出bug的目的的。又或者你對(duì)gdb已經(jīng)很熟了,但運(yùn)行g(shù)db開(kāi)始調(diào)試后在哪里設(shè)置斷點(diǎn)成了你頭痛的問(wèn)題?當(dāng)然,你可以從程序開(kāi)始就以單步運(yùn)行step by step來(lái)調(diào)試程序,但這會(huì)耗去你很多時(shí)間。
如果你能很好地跟蹤并記錄程序的運(yùn)行情況,那么一切將變得簡(jiǎn)單。下面我以一個(gè)實(shí)例說(shuō)明我是如何操作的:
首先我有一個(gè)程序主體main,其代碼如下:
//trace.c 開(kāi)始///
/*********************************************************************
*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) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循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 結(jié)束///
這個(gè)main里面引用了global.h,MyFuncOne.h,MyFuncTwo.h等,global.h里面是一個(gè)宏定義,定義了dump宏,其內(nèi)容如下:
//global.h 開(kāi)始///
#ifndef GLOBAL_H
?? ?#define GLOBAL_H
?? ?#include "dump.h"
/*********************************************************************
*filename: global.h
*purpose: dump function declare
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
?? ?#ifdef DEBUG
?? ??? ?#define dump(fp, x...)? debug_print(fp, __FILE__, __LINE__, __FUNCTION__, ##x);
?? ?#else
?? ??? ?#define dump(fp, x...)
?? ?#endif
#endif
//global.h 結(jié)束///
global.h這里又引用了dump.h,其內(nèi)容稍后再貼出來(lái)。
MyFuncOne.h和MyFuncTwo.h分別定義了兩個(gè)函數(shù)MyFuncOne和MyFuncTwo,其內(nèi)容如下:
//MyFuncOne.h 開(kāi)始///
#ifndef MYFUNC_ONE_H
?? ?#define MYFUNC_ONE_H
?? ?#include "global.h"
/*********************************************************************
*filename: MyFuncOne.h
*purpose: MyFuncOne function declare
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
?? ?void MyFuncOne();
#endif
//MyFuncOne.h 結(jié)束///
//MyFuncTwo.h 開(kāi)始///
#ifndef MYFUNC_TWO_H
?? ?#define MYFUNC_TWO_H
?? ?#include "global.h"
/*********************************************************************
*filename: MyFuncTwo.h
*purpose: MyFuncTwo function declare
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
?? ?void MyFuncTwo();
#endif
//MyFuncTwo.h 結(jié)束///
//MyFuncOne.c 開(kāi)始///
#include "MyFuncOne.h"
extern int x;
/*********************************************************************
*filename: MyFuncOne.c
*purpose: MyFuncOne function instance
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
void MyFuncOne()
{
?? ?x *= -2;
?? ?dump(stdout, "MyFuncOne, now: x=%d", x);
}
//MyFuncOne.c 結(jié)束///
//MyFuncTwo.c 開(kāi)始///
#include "MyFuncTwo.h"
extern int x;
/*********************************************************************
*filename: MyFuncTwo.h
*purpose: MyFuncOne function declare
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
void MyFuncTwo()
{
?? ?x++;
?? ?dump(stdout, "MyFuncTwo, now: x=%d", x);
}
//MyFuncTwo.c 結(jié)束///
現(xiàn)在該是時(shí)候說(shuō)dump了,先看看其實(shí)現(xiàn):
//dump.h 開(kāi)始///
#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) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循GPL?? ??? ?
*********************************************************************/
?? ?void debug_print(FILE * fp, const char * filename, const int line, const char * funcname, char *fmt, ...);
#endif
//dump.h 結(jié)束///
//dump.c 開(kāi)始///
#include "dump.h"
/*********************************************************************
*filename: dump.c
*purpose: debug_print function instance
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
*date time:2005-11-30 00:30
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些代碼,當(dāng)然包括你的商業(yè)用途
*???????????????????????? 但請(qǐng)遵循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 結(jié)束///
大家一定注意到:這個(gè)程序和大家一般寫(xiě)的程序并無(wú)大的區(qū)別,除了__FILE__, __LINE__, __FUNCTION__等幾個(gè)宏和dump宏,__FILE__, __LINE__, __FUNCTION__是編譯的時(shí)候已經(jīng)內(nèi)置了的幾個(gè)宏,用來(lái)表明當(dāng)前程序運(yùn)行到了哪個(gè)源文件的哪一行,同時(shí)表明當(dāng)前在哪個(gè)函數(shù)里面。而我們定義一個(gè)dump宏就是用來(lái)把這些信息送到一個(gè)文件句柄去。比如你的日志文件。這樣,在任何程序需要的地方都可以加上一句dump來(lái)把需要的調(diào)試信息記錄下來(lái)。
比如編譯上述程序:
gcc -DDEBUG trace.c dump.c MyFuncOne.c MyFuncTwo.c -o trace
然后運(yùn)行程序可以得到如下結(jié)果:
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函數(shù)內(nèi)打印出:now: x=5;
第二行:顯示在MyFuncOne.c源文件的第15行處,即MyFuncOne函數(shù)內(nèi)打印出:MyFuncOne, now: x=-10;
第三行:顯示在MyFuncTwo.c源文件的第15行處,即MyFuncTwo函數(shù)內(nèi)打印出:MyFuncTwo, now: x=-9;
第四行:顯示在trace.c源文件的第25行處,即main函數(shù)內(nèi)打印出:now: x=-9;
如果程序加多點(diǎn)dump,則程序運(yùn)行到了哪里出了問(wèn)題就會(huì)一目了然了。
轉(zhuǎn)自:http://zhoulifa.bokee.com/3700951.html
轉(zhuǎn)載于:https://www.cnblogs.com/fly-fish/archive/2011/03/11/1981708.html
總結(jié)
以上是生活随笔為你收集整理的利用__FILE__, __LINE__, __FUNCTION__跟踪调试程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 什么叫文章?
- 下一篇: 家有儿女中有一句话就是我学习不好,你怎么