I am using the following macro for printing debug information that I found on the web. It works great.
However, I would like to turn-off debug printing for function A when debugging function B, which calls function A. I tried #define NDEBUG function A #undef NDEBUG but haven't managed to suppress printing in function A.
Any help will be greatly appreciated.
Any suggestions for alternative ways of accomplishing the task is also welcome.
Thanks ~RT
#ifdef NDEBUG
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
maybe you should wrap the trace into a module so that you can turn on/off the tracing dynamically in run-time and in that way you can specifically turn it off for a function call. In release mode you could replace all tracing with empty statements although in my experience I find it good to keep tracing in release mode as well - just in case.
NDEBUG is useful at the time assert.h is included, so #define NDEBUG/#undef NDEBUG later will not do anything.
You can do something like this though:
#if defined(NDEBUG) || !defined(MY_DEBUG)
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
Then, in function A():
...
#undef MY_DEBUG
result = B();
#define MY_DEBUG
...
This will debug B() when it's called from anywhere except from A(). To get debugging, you will need MY_DEBUG to be defined and NDEBUG to be undefined.
Edit: You will need to define MY_DEBUG when you want to compile with debugging, but hopefully you're using make or some other build tool, so this should be easy.
Related
This question already has answers here:
#define macro for debug printing in C?
(14 answers)
Closed 1 year ago.
I would like to have a conditional print macro where I can toggle it on or off based upon whether a macro is defined, such as #define DEBUG. My first thought was the following:
#define DEBUG_PRINT(...) #ifdef DEBUG printf(__VA_ARGS__) #endif
But this doesn't quite work and I get the following error when trying:
pc.c:16:24: error: '#' is not followed by a macro parameter
#define DEBUG_PRINT(...) #ifdef DEBUG printf(__VA_ARGS__) #endif
What would be a valid way to define something like a DEBUG_PRINT macro which prints if a boolean value is turned on?
The canonical way to do this is:
#ifdef DEBUG
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
In case you need/want to execute multiple statements:
#define DEBUG_PRINT(...) do { printf(__VA_ARGS__); xxx; yyy; } while (0)
See also: do { ... } while (0) — what is it good for?
Finally, you probably should prefer fprintf(stderr, __VA_ARGS__) instead of just printf for debugging.
my code:
#define DEBUG 3
#define TEST(...)
#if (DEBUG == 3) \
printf("%s: %s\n", __FILE__, __VA_ARGS__);
#endif
int main(void) {
TEST("TEST")
return 0;
}
Error: missing the binary operator before token 'printf'.
I don't understand what's the problem
You're trying to put the #if inside the macro, but C doesn't permit that kind of thing. The reason it's failing is the printf inside the #if is unexpected. This is a common request, but it's just not allowed.
However, you can accomplish the same thing by changing the way you do the test:
#include <stdio.h>
#define DEBUG 3
#if (DEBUG == 3)
# define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__);
#else
# define TEST(...)
#endif
int main(void) {
TEST("TEST")
return 0;
}
EDIT: Though test-type macros like this are common, this is not a great way to do it because it can lead to unhappy surprises in debug/nondebug situations.
What happens in this case?
if (something)
TEST("blah")
else
TEST("no")
This works as you expect in debug mode, but won't even compile in production because it devolves to if (something) else - it doesn't even have a closing semicolon. It's easy to find other examples that are much more devious.
Hiding a semicolon inside a macro like this is usually asking for trouble, so the better approach is to make them function-like where you have to provide the semicolon yourself, and the most obvious way to do it is:
# #define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__) // no semicolon
...
if (something)
TEST("blah");
else
TEST("no");
This is better and leads to less surprises, but it's still a little troublesome in that it can leave a dangling semicolon lying around, which some compilers object to.
A fix for this can be:
#if (DEBUG == 3)
# define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__)
#else
# define TEST(...) ((void)0) // dummy statement
#endif
which at least quiets the compiler. There are other approaches here too.
In C #define cannot "contain" #ifs
I use a LOG_DEBUG function to print debug information to the screen. I used a #define _DEBUG to disable LOG_DEBUG function by defining _DEBUG FLAG in compile time (release time). but linux strings commands of release build app still shows debug strings which exists in the compiled app. so what is the alternatives to eliminate arguments of LOG_DEBUG?
#ifdef _DEBUG
#define LOG_DEBUG(fmt, ...) printf("[D][%s:%d %s]", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
#define LOG_DEBUG(fmt, ...)
#endif
LOG_DEBUG("this is a debug string"); // "this is a debug string" exists in app release build yet
the compiler I use: ARM/Thumb C/C++ Compiler, RVCT3.1 [Build 569]
optimization: -O3
You could try using stringification:
#include <stdio.h>
#define _DEBUG
#ifdef _DEBUG
#define LOG_DEBUG(str) do { printf("[D][%s:%d %s] ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
puts(#str); } while(0)
#else
#define LOG_DEBUG(str)
#endif
int main() {
LOG_DEBUG(this is a debug string);
return 0;
}
Note: I tested this in clang, which doesn't exhibit the behaviour you described.
I'm trying to do a debug system but it seems not to work.
What I wanted to accomplish is something like this:
#ifndef DEBUG
#define printd //
#else
#define printd printf
#endif
Is there a way to do that? I have lots of debug messages and I won't like to do:
if (DEBUG)
printf(...)
code
if (DEBUG)
printf(...)
...
No, you can't. Comments are removed from the code before any processing of preprocessing directives begin. For this reason you can't include comment into a macro.
Also, any attempts to "form" a comment later by using any macro trickery are not guaranteed to work. The compiler is not required to recognize "late" comments as comments.
The best way to implement what you want is to use macros with variable arguments in C99 (or, maybe, using the compiler extensions).
A common trick is to do this:
#ifdef DEBUG
#define OUTPUT(x) printf x
#else
#define OUTPUT(x)
#endif
#include <stdio.h>
int main(void)
{
OUTPUT(("%s line %i\n", __FILE__, __LINE__));
return 0;
}
This way you have the whole power of printf() available to you, but you have to put up with the double brackets to make the macro work.
The point of the double brackets is this: you need one set to indicate that it's a macro call, but you can't have an indeterminate number of arguments in a macro in C89. However, by putting the arguments in their own set of brackets they get interpreted as a single argument. When the macro is expanded when DEBUG is defined, the replacement text is the word printf followed by the singl argument, which is actually several items in brackets. The brackets then get interpreted as the brackets needed in the printf function call, so it all works out.
С99 way:
#ifdef DEBUG
#define printd(...) printf(__VA_ARGS__)
#else
#define printd(...)
#endif
Well, this one doesn't require C99 but assumes compiler has optimization turned on for release version:
#ifdef DEBUG
#define printd printf
#else
#define printd if (1) {} else printf
#endif
On some compilers (including MS VS2010) this will work,
#define CMT / ## /
but no grantees for all compilers.
You can put all your debug call in a function, let call it printf_debug and put the DEBUG inside this function.
The compiler will optimize the empty function.
The standard way is to use
#ifndef DEBUG
#define printd(fmt, ...) do { } while(0)
#else
#define printd(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
That way, when you add a semi-colon on the end, it does what you want.
As there is no operation the compiler will compile out the "do...while"
Untested:
Edit: Tested, using it by myself by now :)
#define DEBUG 1
#define printd(fmt,...) if(DEBUG)printf(fmt, __VA_ARGS__)
requires you to not only define DEBUG but also give it a non-zer0 value.
Appendix:
Also works well with std::cout
In C++17 I like to use constexpr for something like this
#ifndef NDEBUG
constexpr bool DEBUG = true;
#else
constexpr bool DEBUG = false;
#endif
Then you can do
if constexpr (DEBUG) /* debug code */
The caveats are that, unlike a preprocessor macro, you are limited in scope. You can neither declare variables in one debug conditional that are accessible from another, nor can they be used at outside function scopes.
You can take advantage of if. For example,
#ifdef debug
#define printd printf
#else
#define printd if (false) printf
#endif
Compiler will remove these unreachable code if you set a optimization flag like -O2. This method also useful for std::cout.
As noted by McKay, you will run into problems if you simply try to replace printd with //. Instead, you could use variadric macros to replace printd with a function that does nothing as in the following.
#ifndef DEBUG
#define printd(...) do_nothing()
#else
#define printd(...) printf(__VA_ARGS__)
#endif
void do_nothing() { ; }
Using a debugger like GDB might help too, but sometimes a quick printf is enough.
I use this construct a lot:
#define DEBUG 1
#if DEBUG
#if PROG1
#define DEBUGSTR(msg...) { printf("P1: "); printf( msg); }
#else
#define DEBUGSTR(msg...) { printf("P2: "); printf( msg); }
#endif
#else
#define DEBUGSTR(msg...) ((void) 0)
#endif
This way I can tell in my console which program is giving which error message... also, I can search easily for my error messages...
Personally, I don't like #defining just part of an expression...
It's been done. I don't recommend it. No time to test but the mechanism is kind of like this:
#define printd_CAT(x) x ## x
#ifndef DEBUG
#define printd printd_CAT(/)
#else
#define printd printf
#endif
This works if your compiler processes // comments in the compiler itself (there's no guarantee like the ANSI guarantee that there are two passes for /* comments).
in C, what is the proper way to define a printf like macro that will print only when DEBUG symbol is defined?
#ifdef DEBUG
#define DEBUG_PRINT(???) ???
#else
#define DEBUG_PRINT(???) ???
#endif
where ??? is where I am not sure what to fill in
I've seen this idiom a fair amount:
#ifdef DEBUG
# define DEBUG_PRINT(x) printf x
#else
# define DEBUG_PRINT(x) do {} while (0)
#endif
Use it like:
DEBUG_PRINT(("var1: %d; var2: %d; str: %s\n", var1, var2, str));
The extra parentheses are necessary, because some older C compilers don't support var-args in macros.
#ifdef DEBUG
#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while( false )
#else
#define DEBUG_PRINT(...) do{ } while ( false )
#endif
Something like:
#ifdef DEBUG
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, fmt, ## args)
#else
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#endif
Thank you mipadi, I improved your DEBUG_PRINT with file information too.
#define DEBUG 3
#if defined(DEBUG) && DEBUG > 0
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \
__FILE__, __LINE__, __func__, ##args)
#else
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#endif
Tested with latest clang, e.g.
int main(int argc, char **args) {
DEBUG_PRINT("Debugging is enabled.\n");
DEBUG_PRINT("Debug level: %d", (int) DEBUG);
}
outputs:
DEBUG: debug.c:13:main(): Debugging is enabled.
DEBUG: debug.c:14:main(): Debug level: 3
Use different signatures of DEBUG_PRINT, they don't have to be the same, like:
#ifdef DEBUG
#define DEBUG_PRINT printf
#else
#define DEBUG_PRINT(...)
#endif
this way on debug mode the DEBUG_PRINT call will be replaced with printf. On release it will ignore all arguments used previously.
Hope it helps.
You can simply use:
#ifdef DEBUG
#define DEBUG_PRINT printf
#else
#define DEBUG_PRINT
#endif
I like this way the best because it wont add any asm instructions to your release build.
#define DEBUG
#ifdef DEBUG
#define debug_printf(fmt, ...) printf(fmt, __VA_ARGS__);
#else
#define debug_printf(fmt, ...) /* Do nothing */
#endif
I see some minor errors in this implementation. So, here is my approach:
#ifdef DEBUG
#define DEBUG_PRINTF(...) printf("DEBUG: "__VA_ARGS__)
#else
#define DEBUG_PRINTF(...) do {} while (0)
#endif
Example usage:
DEBUG_PRINTF("hello\n");
Then, if I build and run with the -DDEBUG define on in my C build options, like this:
# Build
gcc -Wall -Wextra -Werror -std=c11 -DDEBUG -o build/my_program \
my_program_tests.c my_program.c
# Run
build/my_program
then I see this output:
DEBUG: hello
But if I build withOUT the -DDEBUG define in my compiler C options, then I see no debug prints whatsoever.