Enable/Disable LOG levels using C Macro - c

#include <stdio.h>
#define LOG_D(x) { printf("D:"); printf(x);}
#define LOG_E(x) { printf("E:"); printf(x);}
void test(void)
{
LOG_D("ALL is well " );
}
I have a very huge code it has different levels of log, like above code.
In the final tested library I just need only one error logs in order to reduce the code size .
so I want something like this
#define ENABLE_DEBUG_LOG 0
#define ENABLE_ERROR_LOG 1
#define LOG_D(x) {#if(ENABLE_DEBUG_LOG==1) printf("D:"); printf(x); #endif}
#define LOG_E(x) {#if(ENABLE_ERROR_LOG==1) printf("E:"); printf(x);#endif}
I added this #if(ENABLE_DEBUG_LOG==1) just for explaining, I need some solution which can compile.

Another option - you can just comment / uncomment ENABLE_DEBUG_LOG and ENABLE_ERROR_LOG to disable / enable corresponding log level.
// #define ENABLE_DEBUG_LOG // disable DEBUG_LOG
#define ENABLE_ERROR_LOG // enable ERROR_LOG
#ifdef ENABLE_DEBUG_LOG
#define LOG_D(x) { printf("D:"); printf(x);}
#else
#define LOG_D(x) // nothing
#endif
#ifdef ENABLE_ERROR_LOG
#define LOG_E(x) { printf("E:"); printf(x);}
#else
#define LOG_E(x) // nothing
#endif

You cannot nest preprocessor directives. But you can make two versions of your macro and define them in exclusive parts of an #if or #ifdef:
#define ENABLE_DEBUG_LOG 0
#if ENABLE_DEBUG_LOG != 0
#define LOG_D(...) printf("D: " __VA_ARGS__)
#else
#define LOG_D(...) // Do nothing
#endif
Here, the disabled version just "eats" the LOG_D macro and doesn't do anything. (Note that undefined macros are treated as the value 0 in #if conditionals.)

You should be able to do something like this:
#if ENABLE_DEBUG_LOG == 1
# define LOG_D(x) { printf("D:"); printf(x);}
#else
# define LOG_D(x)
#end
That way the debug log statements will just disappear if ENABLE_DEBUG_LOG is undefined or has a different value.

Regarding the other answers, it is not good idea to define the macros completely empty when they are not enabled, as this would go wrong when error logging is enabled:
if (some_error)
LOG_E("Oops...");
do_something();
If LOG_E(x) expands to nothing, then do_something() would only be called if some_error is true, which is probably not what you want!
So you could define the "do nothing" variant of LOG_E(x) like this:
#define LOG_E(x) { }
Rather than starting and ending with braces, I tend to use the do { blah; } while (0) construct as it forces you to put a semicolon on the end when you use it. Something like this:
#if ENABLE_ERROR_LOG
#define LOG_E(x) do { printf("E:"); printf(x); } while (0)
#else
#define LOG_E(x) do ; while (0)
#endif
Then,
if (some_error)
LOG_E("Oops")
would result in a syntax error because of the missing semicolon, forcing you to write it as
if (some_error)
LOG_E("Oops");
Another thing you can do is concatenate the "E:" or "D:" tag with the passed in string, although this requires the parameter to be a string literal, rather than a general char *:
#define LOG_E(x) printf("E:" x)
Another thing you can do is to define the macro with a variable number of parameters (a variadic macro) to increase your options:
#define LOG_E(...) printf("E:" __VA_ARGS__)
Then you can do:
if (some_error)
LOG_E("Oops, got error: %d\n", some_error);
Another thing you can do is let the compiler optimize out the call to printf and define it like this:
#define LOG_E(...) do if (ENABLE_ERROR_LOG) printf("E:" __VA_ARGS__); while (0)
A decent compiler will notice that the if condition is constant and either optimize out the call to printf completely (if the constant condition is false), or include it (if the constant condition is true). For some compilers, you might need to suppress warnings about constant conditions in an if statement.

I am not sure if this is what you want, but you could check the #ifdef directive.
#include <stdio.h>
/* #define DEBUG */
#ifdef DEBUG
#define LOG_D(x) { printf("D: %s\n",x); }
#define LOG_E(x) { printf("E: %s\n",x); }
#else
#define LOG_D(x)
#define LOG_E(x)
#endif
int main() {
LOG_D("blah...");
return 0;
}
If you uncomment the #define DEBUG line, the program will print D: blah...

Related

Using macro statement in macro function in C

Using #ifdef <macro> <statement> #endif allows one to have verbose messages displayed only during development and is quite handy. I wonder if something like the code below is possible, becoming even shorter:
// pseudo-code:
#define IN_DEV
#define DEBUG_ONLY(statement) (#ifdef IN_DEV (statement) #endif)
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
This would only cost me a very readable one-liner which can be turned on or off. Is something like this / close to this possible?
You could change the meaning of DEBUG_ONLY dependent on if IN_DEV is defined:
// pseudo-code:
#ifdef IN_DEV
#define DEBUG_ONLY(statement) {statement}
#else
#define DEBUG_ONLY(statement) // Nothing
#endif
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
Running example: Link
It doesn't make much sense to pass whole expressions as parameters to macros. That is both dangerous and unmaintainable. Worse yet, it's taking us down the obfuscation road of "lets invent our own private macro language instead of using readable C that anyone can understand". That's a terrible idea even for debugging purposes.
The more sensible approach would be a function-like printing macro which only prints something in debug build.
#ifdef INDEV
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
int main(void)
{
DEBUG_PRINT("hello from debug mode\n");
}
Optionally this macro can be narrowed down to only accept strings and be made more type safe (C17 only):
#ifdef INDEV
#define DEBUG_PRINT(str) _Generic((str), char*: puts(str))
#else
#define DEBUG_PRINT(str) _Generic((str), char*: (void)0)
#endif
That is not possible. You cannot use #if inside a macro definition.
What you can do is this:
#define IN_DEV
#ifdef
#define DEBUG_ONLY(statement) (statement)
#else
#define DEBUG_ONLY(statement)
#endif
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
This is also switchable with only a single macro IN_DEV.

Using #ifdef on token-pasted macros?

I know there is already a similar post to mine (C++ `ifdef` with concatenation of macros values) but the post is pretty old and the solution provided does not work for me, because I cannot set the define I want to check. So I hope someone can help me.
The problem is that I want to make an ifdef of a concatenation of two a define with a fixed text.
Imagine the following code
#define ENABLE_MODULE_1
enum Modultype
{
MODULE_1,
MODULE_2
};
#define MODULE MODULE_1
int main()
{
#ifdef ENABLE_ ## MODULE
printf("NAME defined");
#else
printf("NAME not defined");
#endif
return 0;
}
So I basically want to check if ENABLE_MODULE_1 is defined based on the MODULE define.
I hope someone can help me. Thanks!
This is not possible. Preprocessor macros only expand once, and only when not in another preprocessor statement. Along with that, concatenations can only be used within a #define statement.
You cannot do precisely what you want because #ifdef operates on an identifier, not a preprocessor expression, and the ## operator can only be used in the replacement text of a macro definition.
If you are willing to define ENABLE_MODULE_1 (if defined at all) with a non-zero constant as its replacement text, you can achieve something similar to what you want as follows:
#include <stdio.h>
#define XENABLED(x) ENABLE_ ## x
#define ENABLED(x) XENABLED(x)
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define ENABLE_MODULE_1 1 /* enabled */
#define ENABLE_MODULE_3 0 /* not enabled */
#define MODULE MODULE_1
#define OTHER MODULE_2
#define ANOTHER MODULE_3
int main(void)
{
#if ENABLED(MODULE)
printf("%s enabled\n", STR(MODULE));
#else
printf("%s not enabled\n", STR(MODULE));
#endif
#if ENABLED(OTHER)
printf("%s enabled\n", STR(OTHER));
#else
printf("%s not enabled\n", STR(OTHER));
#endif
#if ENABLED(ANOTHER)
printf("%s enabled\n", STR(ANOTHER));
#else
printf("%s not enabled\n", STR(ANOTHER));
#endif
#if ENABLED(UNDEFINED)
printf("%s enabled\n", STR(UNDEFINED));
#else
printf("%s not enabled\n", STR(UNDEFINED));
#endif
return 0;
}
The above program produces the following output:
MODULE_1 enabled
MODULE_2 not enabled
MODULE_3 not enabled
UNDEFINED not enabled

How to define macro bases on macro value?

I have macros:
#if defined DEBUG && DEBUG
# define D(...) printf(__VA_ARGS__)
#else
# define D(...)
#endif
Which effectively do nothing when DEBUG has TRUE value.
But now I want to provide the TYPE thing. Which will show the type of debugging:
D( 1, "some string" );
D( 2, "another thing" );
Is there a way to define such macros which will do nothing for D(1,..) and print debug messages for D(2,...) when DEBUG is 2 and viceversa when 1?
I wanna something like this::
#if defined DEBUG && DEBUG
# define D(type,...) if DEBUG&type THEN printf(__VA_ARGS__) else do nothing
#else
# define D(...)
#endif
Well, it won't be truely evaluated at preprocessing time, but if the type is a compile-time-constant, still at compile-type.
#define D(type, ...) (void)((type & DEBUG) && fprintf(stderr, __VA_ARGS__))
The above needs at least C99 though.
You can do it like this;
#if defined DEBUG
# define P1(...)
# define P2(...) printf(__VA_ARGS__)
# define D(n, ...) P##n(__VA_ARGS__)
#else
# define D(...)
#endif
main()
{
D(1, "Test");
D(2, "Test2");
}
This did not resolve the problem but take me closer. Maybe it will be useful for someone:
#define _CAT(a, ...) a ## __VA_ARGS__
#define CHECK(...) SECOND(__VA_ARGS__, 0)
#define SECOND(x, n, ...) n
#define _NOT_0 _TRUE()
#define _TRUE() ~, 1
#define BOOL(x) NOT(NOT(x))
#define NOT(x) CHECK(_CAT(_NOT_, x))
#define IF(cond) _IF(BOOL(cond))
#define _IF(cond) _CAT(_IF_, cond)
#define _IF_1(...) __VA_ARGS__
#define _IF_0(...)
IF(1)(printf("YES\n");)
IF(0)(printf("NO\n");)
Links to tricks: first and second. Second link is more interesting because it describes what is coming on step-by-step

print only if _DEBUG defined: c

I want to print info only if _DEBUG is defined
#define DEBUG(y) y == true ? #define _DEBUG true : #define _DEBUG false
#ifdef _DEBUG
#define Print(s) printf(s);
#endif
Getting Error:
error: '#' is not followed by a macro parameter
Any suggestion how to achieve this with pre-processor directives?
I intend to use it from my main as:
DEBUG(true);
Print("Inside main in debug mode");
You cannot redefine a MACRO at run-time.
Neither you can have a #define inside of another #define, like you try in the first line of your code.
You can do something like this:
#ifdef _DEBUG
#define Print(s) printf("%s", s)
#else
#define Print(s)
#endif
And use it from your main as:
#define _DEBUG
Print("Inside main in debug mode");
#undef _DEBUG
Print("Inside main debug mode off");
If you really need to switch debug on and off at run-time, your can do something like this:
void PrintIf(BOOL dbg, char * msg)
{
if (dbg)
{
printf("%s", msg)
}
}
And use it like this
y = TRUE;
PrintIf(y,"Inside main in debug mode");
y = FALSE;
PrintIf(y,"Inside main debug mode off");
Try this:
#ifdef DEBUG
#define Print(s) printf("%s", s)
#else
#define Print(s)
#endif
Then:
#define DEBUG
Print("Inside main in debug mode");
I intend to use it from my main as:
DEBUG(y);
Print("Inside main in debug mode");
Sorry, but ifdef are compile time (not run-time). You could use a global bool and runtime checking to enable and disable debug.
You can't create preprocessor statements with macros as you are trying to do; it doesn't work and isn't allowed. For conditional printing, see C #define macro for debug printing.
The problem occurs here:
#define DEBUG(y) y == true ? #define _DEBUG true : #define _DEBUG false
When introducing #defines, the definition # occurs at the beginning of the line, not later (although) preprocessors generally allow one or two line indents.) You need to rewrite your #define eliminating the ternary operator simply as:
#ifdef _DEBUG
#define Print(s) printf(s);
#endif
While you may extend you defines with macros, you often introduce additional errors. It is generally better to stick to wrapping your _DEBUG code simply in #ifdef statements:
#ifdef _DEBUG
fprintf (stderr, "your error messages\n"); // using standard printf/fprintf instead of macros
...
#endif /* _DEBUG */
Macros are substituted at preprocessing stage and
#define DEBUG(y) y == true ? #define _DEBUG true : #define _DEBUG false
this statement will be evaluated at compile time.
Conditional operator (ternary operator) are evaluated at compile time. So you are getting this error and # operator must always be used at the beginning of the statement that is the second mistake you are doing.
You can better use it this way
#define DEBUG
printf ("true");
#else
printf ("false");
You can also define this macro dynamically by using the gcc option -D
gcc -D DEBUG filename.c -o outputFile
The first line is incorrect:
#define DEBUG(y) y == true ? #define _DEBUG true : #define _DEBUG false
You cannot use #define inside preprocessor directive (like another #define)
And it does not make sense, since preprocessing happens before the real compilation (so before run time, when your y has some value). Read the cpp preprocessor documentation. Recall that sometimes the preprocessor is even a different program (/lib/cpp) but is today the first phase of most C compilers.
You could ask for the preprocessed form of your source code (e.g. with gcc -C -E source.c > source.i if using GCC) and look at that form with a pager (less source.i) or your editor.

Can you #define a comment in C?

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

Resources