#define DEBUG 1

32

我正在尝试开启调试模式,以便如果

#define DEBUG 1

我想要用printf输出一些变量的值,如果

#define DEBUG 0

我想关闭它们。

问题是我有许多实现文件,我希望这个DEBUG变量在整个项目中都可用。目前,我需要在foo1.c、foo2.c、foo3.c中编辑DEBUG变量,这似乎很繁琐且容易出错,肯定有更好的方法。有什么建议吗?

8个回答

85

编译时,你可以向编译器指定选项。例如,你可以使用 -DDEBUG 选项调用 GCC。

在这种情况下,最好使用:

#ifdef DEBUG
#endif
或者:
#if defined(DEBUG)
#endif

如果这不是你现在的做法,我很惊讶你的项目中没有全局头文件。可以考虑创建一个类似于以下内容的文件:

#undef DEBUG
#define DEBUG 1

在一个名为"debug.h"的文件中。在你的C程序中,你可以使用#include "debug.h"来包含它。


4
难道不应该是 gcc -DDEBUG 而不是 -dDEBUG 吗? - Alan Haggai Alavi
2
nop... -D 是正确的选项(-U 用于未定义)-d 加上一个字母是为了在编译时在指定的时间进行调试转储。 - LB40
1
@Alan,我误解了你的意思...我的错 :-) - LB40
@person-b 和 @LB:我应该重新表达一下我的评论。它看起来有歧义。 :-) - Alan Haggai Alavi
3
不需要使用序列:#ifdef X / #undef X / #endif;只需写:#undef X。已经多年,当X未定义时不喜欢这种方法的编译器已经消失了;C89标准规定取消未定义宏不是错误。 - Jonathan Leffler

17

尝试像Steve McConnel在Code Complete 2的“第8章:防御性编程”的第6节中建议的那样做...将此添加到您的代码中:

#ifdef DEBUG
#if (DEBUG > 0) && (DEBUG < 2)
printf("Debugging level 1");
#endif

#if (DEBUG > 1) && (DEBUG < 3)
printf("Debugging level 2");
#endif

#if (DEBUG > n-1) && (DEBUG < n)
printf("Debugging level n");
#endif
#endif

编译时,请添加此标志(警告:这可能取决于编译器):

-DDEBUG=m

或者,像其他人建议的那样,有一个定义这些内容的全局标头。

不错的建议,但是这本书叫什么名字? - Simon Puente

6
作为对您问题的回应,您也可以简单地调用编译器,例如:
cc -c -DDEBUG=1 

或者

 cc -c -DDEBUG=0

您必须删除您的文件中的"define DEBUG 1/0" - 或者将其替换为:

#ifndef DEBUG
#define DEBUG 0
#endif

我现在正在使用的是(GCC语法):

  • create a file debug.h with the following content and include it in each c file:

    #ifdef DEBUG
    extern FILE *dbgf;
    #define D_MIN   0x00010000  // Minimum level
    #define D_MED   0x00020000  // Medium level
    #define D_MAX   0x00040000  // Maximum level 
    #define D_FLUSH 0x00080000  // Usefull by a program crash
    #define D_TRACE 0x00100000  
    #define D_1     0x00000001  
    ...
    
    #define D(msk, fmt, args...) if(msk & dbgmsk) { fprintf(dbgf, "%s:",__FUNCTION__); fprintf(dbgf, fmt, ## args ); if(msk & D_FLUSH) fflush(dbgf); }
    #define P(msk, fmt, args...) if(msk & dbgmsk) { fprintf(dbgf, fmt, ## args ); if(msk & D_FLUSH) fflush(dbgf); }
    
    #else
    #define D(msk, fmt, args...)
    #define P(msk, fmt, args...)
    #endif
    

dbgmsk是一个变量,它可以是全局的(整个程序)或者是局部/静态的,并且必须在开始时初始化。你可以为整个程序或每个模块定义多个选项。这比带有级别变量的版本更好、更灵活。

例如:

module1.c:
#include "debug.h"

static int dbgmsk;  // using local dbgmsk
module1_setdbg(int msk) { dbgmsk = msk; D(D_TRACE,"dbgmsk1=%x\n", dbgmsk); }

foo1() {  P(D_1, "foo1 function\n" ); 
  ....
}
foo2() {}
...

foo3.c

#include "debug.h"
extern int dbgmsk; // using global dbgmsk

例如,主函数:

#include "debug.h"
FILE *dbgf;
int dbgmsk = 0; // this is the global dbgmsk

int main() { 
  dbgf = stderr; // or your logfile
  dbgmsk = D_MIN;
  module1_setdbg(D_MIN|D_MED|D_TRACE|D_1);
  ....
}

我还将所有dbgmsk变量存储在一个配置文本文件中,在程序启动时读取该文件。

最好确保编译器始终看到但不总是执行诊断打印。#else子句应该做类似这样的事情:#define D(msk, fmt,...) do { if(0 &&(msk & dbgmsk)) printf(fmt,__VARARGS__);} while(0)。do / while成语确保您可以在语句出现的任何地方使用它;if(0)意味着代码永远不会被执行,并且编译器将优化它,但仅在检查它的语法有效性之后。如果将非调试版本定义为空,则不会持续检查调试代码的语法有效性。 - Jonathan Leffler

5

正如@person-b所说,将此定义指定为编译器选项,例如 -D DEBUG。

请注意,为了简化此过程,您应该更改代码中的测试,从而避免以下情况:

#if DEBUG

to:

#ifdef DEBUG

这样,您就不必担心指定0或1值,而是可以依赖它是否已定义。

4
将"#define DEBUG"放在"debug.h"文件中,并在每个*.c文件中包含该头文件。

1
也许这不是正确的方法。 使用Makefile管理构建模式,DEBUG或RELEASE。 因此,根据构建模式,变化CFLAGS中的内容。 这种方法将无缝扩展。 - ϹοδεMεδιϲ

2

来自samoz和Stephen Doyle的建议是检查DEBUG的定义是否存在,而不是它的值,这是一个好建议。然而,如果你真的想使用DEBUG=0,那么你可以这样做:每次你定义DEBUG标志(即在每个文件中),都要检查是否存在已定义:

#ifndef DEBUG
#define DEBUG 1
#endif

然后,当您使用编译器选项 -DDEBUG=0 时,#define 行将永远不会被执行。


我会将默认设置反转 - DEBUG通常为0,但可在命令行上被覆盖。 - Jonathan Leffler

1

可以试试这个。

在你将要包含的第一个文件中:

#define DEBUG

每当您想要调试代码时,请执行以下操作:

#ifdef DEBUG
do some stuff
#endif

这也可以防止您的调试代码进入发布的代码中。


我认为你没有理解他的问题。 - Alex Brown

1

我个人喜欢

#ifdef DEBUG
#define IFDEBUG if(0)else
#else
#define IFDEBUG if(1)else
#endif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接