tags:

views:

2527

answers:

9
+3  Q: 

#define DEBUG 1

I'm trying to have a debugging mode on so if

#define DEBUG 1

I want to printf some variable values and if

#define DEBUG 0

I want them off.

The problem is I have many implementation files and I want this DEBUG variable to be available for the whole project. Right now I need to edit the DEBUG variable in foo1.c, foo2.c, foo3.c which seems tedious and error-prone and there must be a better way. Any suggestions?

+29  A: 

When compiling, you should be able to specify an option to your compiler. For example, you can call GCC with the -DDEBUG option.

In this case, you would be better using:

#ifdef DEBUG
#endif

or:

#if defined(DEBUG)
#endif

if this is not the way you're doing it now. I'm surprised that you don't have a global header file for your project. Something along the lines of:

#ifdef DEBUG
#undef DEBUG
#endif
#define DEBUG 1

in a file called "debug.h". In your C programs, you can include this by using #include "debug.h"

Lucas Jones
+1. This is the best way to do it.
Brian
Is it not `gcc -DDEBUG` instead of `-dDEBUG`?
Alan Haggai Alavi
@Alan: Good point!
Lucas Jones
nop... -D is the right option (-U for undef) -d with a letter is to make debugging dumps during compilation at times specified by a letter
LB
@Alan I misunderstood what you said... my bad :-)
LB
@person-b and @LB: I should have rephrased my comment. It looks ambiguous. :-)
Alan Haggai Alavi
There is never a need for the sequence: #ifdef X / #undef X / #endif; you simply write: #undef X. The compilers that did not like that when X was not defined died years ago; the C89 standard mandates that undefining an undefined macro is not an error.
Jonathan Leffler
+4  A: 

Put the "#define DEBUG" in "debug.h" and #include that header file in each *.c file.

Robert
May be not the right way to go.Use the Makefile to manage the build mode, DEBUG or RELEASE.So according to the build mode, vary what goes into the CFLAGS.That approach will scale seamlessly.
CodeMedic
+1  A: 

Try this instead.

In the first file you have that will be included:

#define DEBUG

Then whenever you want to have debug code, do this:

#ifdef DEBUG
do some stuff
#endif

This will also prevent your debugging code from making it into release code.

samoz
I don't think you understood his question.
Alex Brown
+4  A: 

As @person-b says, specify this define as a compiler option, e.g. -D DEBUG

Note though that to simplify this you should change the test in your code from:

#if DEBUG

to:

#ifdef DEBUG

This way you don't have to worry about specifying a 0 or 1 value but can instead rely on it being defined or not.

Stephen Doyle
+1  A: 

The suggestion from samoz and Stephen Doyle to check for the existence of a definition for DEBUG rather than its value is a good one. However, if you really want to use DEBUG=0, this is how you can do it: Each time you define the DEBUG flag (i.e., in each file), check for an existing definition:

#ifndef DEBUG
#define DEBUG 1
#endif

Then, when you use the option -DDEBUG=0 with your compiler, the #define line will never be executed.

Nathan Kitchen
I would reverse the default - DEBUG 0 normally, but overridable on the command line.
Jonathan Leffler
+2  A: 

Here is what I do - though I don't think its a good practice

#define DEBUGMODE 1
#define pdebug(...) do{if(DEBUGMODE)printf(__VA_ARGS__)}while(0)

So now you can use pdebug exactly like you use printf. Except that any pdebug's will not be executed if you change DEBUGMODE to 0.

So code can go like

int x = // do something
pdebug("Did something and got %d\n", x);

pdebug is a variadic macro and it just passes all arguments to printf.

abhinavg
variadic macros are not very portable. avoid it if possible as use stdargs / vprintf instead
George
The problem with that definition of pdebug occurs with: if (somecondition) pdebug(...) else printf(...); -- the trouble being that the 'else' is associated with the 'if' in pdebug and not the 'if' of '(somecondition)'.
Jonathan Leffler
Thanks for pointing that out.Fixed.
abhinavg
+1  A: 

Try something like Steve McConnel suggests in section 6 of "Chapter 8: Defensive Programming" from Code Complete 2... Add this to your code:

#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

Then when you compile, add this flag (warning: This might be compiler-dependent):

-DDEBUG=m

Or, have a global header that defines these sorts of things, as others have suggested.

Pete
A: 

I personally like

#ifdef DEBUG
#define IFDEBUG if(0)else
#else
#define IFDEBUG if(1)else
#endif
Earlz
great as obfuscation methodology...
jpinto3912
+2  A: 

As a response to your problem you can also simply invoke the compiler like:

cc -c -DDEBUG=1

or

 cc -c -DDEBUG=0

You must delete the "define DEBUG 1/0" in your files - or replace it with:

#ifndef DEBUG
#define DEBUG 0
#endif

Here is what I am using (GCC syntax):

  • 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 is variable, which can be global (whole program) or local/static and must be initialized a start. You can define several options for the whole program or for each module. This is better and more flexible than the version with the level variable.

Ex. 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

Ex. main:

#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);
  ....
}

I'm also storing all dbgmsk variables in a config text file that is read at the program start.

bill
It is better to ensure that the compiler always sees, but does not always act upon, the diagnostic printing. The #else clause should do something like: #define D(msk, fmt, ...) do { if (0 } while (0). The do/while idiom ensures that you can use this anywhere a statement can appear; the if (0) means that the code is never executed, and the compiler will optimize it away - but only after checking it for syntactic validity. If you define the non-debug version to nothing, you do not get continuous checking that the debug code is syntactically valid.
Jonathan Leffler
You're right.Thx!
bill