URN Logo
UNIX Resources » Linux » China Linux Forum » C/C++编程版 » 21 » 利用__FILE__, __LINE__, __FUNCTION__等宏跟踪调试程序的运行
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
利用__FILE__, __LINE__, __FUNCTION__等宏跟踪调试程序的运行
 
 
Subject: 利用__FILE__, __LINE__, __FUNCTION__等宏跟踪调试程序的运行
Author: zhoulifa    Posted: 2005-11-30 01:26    Length: 10,363 byte(s)
[Original] [Print] [Top]
利用__FILE__, __LINE__, __FUNCTION__跟踪调试程序

作为一个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"@ ", 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,则程序运行到了哪里出了问题就会一目了然了。
----
来我的web log看看吧http://zhoulifa.bokee.com
[Original] [Print] [Top]
Subject: Re: 利用__FILE__, __LINE__, __FUNCTION__等宏跟踪调试程序的运行
Author: gogoliu    Posted: 2005-12-03 17:18    Length: 708 byte(s)
[Original] [Print] [Top]
这里有个简单的实现,我平常用的。

#include <stdio.h>

#define DEBUG_FILE stdout
#define DEBUG(fmt,...) fprintf (DEBUG_FILE, fmt, ##__VA_ARGS__)
//#define DEBUG(...) fprintf (DEBUG_FILE, __VA_ARGS__) // 形式2
//#define DEBUG(fmt...) fprintf (DEBUG_FILE, fmt) // 形式3

#define MESSAGE_FILE stdout
#define MESSAGE(fmt,...) fprintf (MESSAGE_FILE, fmt, ##__VA_ARGS__)

#define ERROR_FILE stderr
#define ERROR(fmt,...) fprintf (ERROR_FILE, "ERROR: file: %s[line: %i], function: '%s': "fmt,
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
----
良好的沟通能力 和 积极的行动 是成功的钥匙。
[Original] [Print] [Top]
« Previous thread
linux 下音视频采集!
C/C++编程版
21
Next thread »
请问怎么查看c文件的汇编代码
     

Copyright © 2007 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
备案序号: 京ICP备05006143    webmaster: webmaster@unixresources.net
This page created on 2008-07-17 03:52:25, cost 0.088933944702148 ms.