Proper C preprocessor macro no-op - c

For debug logging, I have often seen and used something like
#ifdef DEBUG
#define DLOG(fmt, args...) printf("%s:%d "fmt,__FILE__,__LINE__,args)
#else
#define DLOG(fmt, args...)
#endif
but in a number of places, I have seen the second #define replaced with
#define DLOG(fmt, args...) do {} while (0)
In particular, there's this answer, and the comment on this other answer to the same question suggests that the problem would be in a situation like
if (condition)
DLOG("foo");
though my quick test suggests that the resulting semicolon on the line by itself will serve as the no-op statement inside the conditional.
Is one or the other of nothing and do {} while (0) better? If so, why? Is there something else that's even better?

A semicolon by itself has two drawbacks:
Users of your macro can write it without a semicolon, and the compiler will not complain, and
Some compilers may issue a warning about a possibly stray semicolon.
The do {} while (0) trick addresses both these concerns:
DLOG("foo") // No semicolon
will trigger an error, and the compiler will not warn you about a "stray" semicolon.

See C #define macro for debug printing for an explanation of why you want a different form of no-op. You want to have the compiler parse the debug printing code even when you aren't using it so that errors do not creep in.

The quick answer is that the do/while method lets you have a multi-statement replacement and still use it as a single statement in an if case like you have in your question. For a single expression replacement, I don't think there's any difference.

Related

Controversial __set_task_state(tsk, state_value) macro syntax in linux kernel [duplicate]

This question already has answers here:
Why use apparently meaningless do-while and if-else statements in macros?
(9 answers)
Closed 2 years ago.
I came across this syntax in several macros, in linux kernel 2.4.31 files, but to keep things in focus I am asking regarding __set_task_state(tsk, state_value) macro defined in include/linux/sched.h:
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
What is the "advantage" of defining the above macro with the do while(0) statement ? Any side effects ?
It's more convenient to define it like so :
#define __set_task_state(tsk, state_value) (tsk)->state = (state_value)
There are at least two reasons for defining it using do-while instead of without it.
First, if you define it without do-while then the macro can be used as a function that returns value. If you don't like that you should use do-while wrapper even for single statement macros.
Second reason is similar. If you define it without wrapper then you can use it to assign value:
set_task_state(my_task, state) = different_state;
It would be perfectly legal, but very confusing for anyone reading your code. It works because this expands to:
(my_task)->state = (state) = different_state;
Another reason is for the if-else statements. If you use it like this without the do-while(0) in the macro:
if (check)
__set_task_state(tsk, state_value);
else
do_something_else;
The compiler will complain because of a "else" without associated "if" (e.g. orphan "else") as the macro expansion will translate the above code as two instructions under the "if" without braces:
if (check)
(tsk)->state = (state_value);; <-- The double ";;" separates two instructions under the "if".
<-- This makes the following "else" orphan
<-- This requires to add braces to fix the compilation error
else
do_something_else;
The do-while(0) in the macro makes the grouped instructions appear as a single instruction. Here the expansion is:
if (check)
do { (tsk)->state = (state_value); } while(0); <-- Here, there is a single instruction under the "if"
<-- So the following "else" is syntactically correct
<-- No need to add braces
else
do_something_else;
N.B.: This tip is normally used to group several instructions in a macro to make them appear as a single instruction:
#define MACRO() do { inst1; inst2; inst3;...; } while (0)
This makes the following work without the need of braces:
if (check)
MACRO();
else
do_something_else;
This also avoid severe hidden bugs like this one for example:
while(check)
MACRO();
Without the do-while(0) construct, only the first instruction (i.e. inst1) would be executed in the while(check) loop!
In this link, there are additional tips to avoid traps with the c-preprocessor. The above tip is described in §3.
Since this macro expands to a single line it doesn't make much sense, but there is a side effect, using the do ... version makes the expression not assignable in both directions:
state = __set_task_state(tsk, state_value); // syntax error in the do version
__set_task_state(tsk, state_value) = state; // syntax error in the do version

Conditionally use #warning or #pragma message or nothing

I have a code which uses #warning a lot to signal compile time branches to the user. The code has a lot of configuration option, therefore it is not really clear which bits of the code are actually taken into the compilation.
Once you have chosen the configuration options, those warnings really clutter the output. So I would like to be able to disable them. The easiest way would be wrapping each of those warnings into an #ifdef ... #else construct. But if I was to touch that code again, I need to go through the whole codebase again.
So instead I want to abstract this a bit. However, I am stuck trying to define a macro that calls #warning or #pragma message. The following compiles but does not do the right thing:
#ifdef EMIT_WARNINGS
#define WARNING(s) _Pragma("message(\"Hi\")")
#else
#define WARNING(s)
#endif
WARNING("How can I print this?")
All my attempts of putting s into there have failed. Once I do _Pragma("message(\"" s "\")"), I get that _Pragma expects a single parenthesised string.
Is there anything I can do to abstract this nicely?
All my attempts of putting s into there have failed. Once I do _Pragma("message(\"" s "\")"), I get that _Pragma expects a single parenthesised string.
_Pragma(S) has an effect equivalent to #pragma X, where X is the unstringified form of S. Going backwards, that means that to get the effect of #pragma X in a _Pragma call, you simply need to stringify X.
The fact that part of X is itself a string is misleading you... don't think of these as pieces you're assembling, but rather as a whole. Rather than trying to stringify s and put it inside "message(\"" and "\")", just stringify message(s) itself as a whole, like this:
#ifdef EMIT_WARNINGS
#define WARNING_I(s) _Pragma(#s)
#define WARNING(s) WARNING_I(message(s))
#else
#define WARNING(s)
#endif
WARNING("How can I print this?")
So when warnings are enabled, WARNING("How can I print this?") expands to WARNING_I(message("How can I print this")). That argument to WARNING_I is itself what you would put on a pragma line; it is your X. The definition of WARNING_I then stringifies that, making the correct S for _Pragma.
From https://gcc.gnu.org/onlinedocs/gcc-6.3.0/cpp/Diagnostics.html#Diagnostics
Neither ‘#error’ nor ‘#warning’ macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.

How to create a "C single-line comment" macro

I am trying to create a "single line comment" macro in C, this is used conditionally to comment out lines of codes, according to some global macro definitions. It is the same idea expressed in this article.
Trying many permutations of this code, I keep getting error messages from the compiler.
For example, directly following the code sample from that page:
#define COMMENT SLASH(/)
#define SLASH(s) /##s
#define DEBUG_ONLY COMMENT
DEBUG_ONLY a = b; // <-- line #83
GCC gives the following error:
prog.c:83:1: error: pasting "/" and "/" does not give a valid preprocessing token
prog.c:83: error: expected expression before ‘/’ token
As mentioned, I played with that theme and tried many variations but all fail giving similar diagnostics.
What am I doing wrong, and why doesn't the code from the article compiles well?
It doesn't work because the language specification doesn't allow it. In effect, comment removal happens before macro replacement. Once comments have been removed, // is not a valid token (like the error message says). It can't be generated by macro replacement, and it no longer means "comment".
This is "Translation phases" in the standard. The section numbering differs, but all of C89, C99 and C11 define in phase 3:
Each comment is replaced by one space character.
and then in phase 4:
macro invocations are expanded
A debug macro:
#define DEBUG(x) x
Which can be turned off in production as:
#define DEBUG(x)
Or IIRC #undef (sorry, my C is rusty).
Why not simply just use e.g.
#ifdef DEBUG
a = b;
#endif /* DEBUG */
Less trouble, and just as readable.
With a #define macro, you can't comment out an entire line per se, but you can comment out everything up to the next semi-colon. I find that this method works pretty well.
#define LOG_LVL 111100011
// 987654321
#if(LOG_LVL%10 >= 1 )
#define LOG1 if(1)
#else
#define LOG1 if(0)
#endif//End LOG1 if-block
#if(LOG_LVL%1000 >= 100)
#define LOG3 if(1)
#else
#define LOG3 if(0)
#endif//End LOG3 if-block
As long as you are careful with your semicolons, this should work fine. By default a non-braced if statement will only execute the following line.
The other benefit of doing logging like this is that you can fine tune what level of logging you want. In this example LOG1 is enabled and LOG3 is disabled. If i wanted my logging to be more verbose, i can quickly change LOG_LVL 111100011 to have a 1 (or higher) in it's 3 digit so that LOG3 will be enabled.
I used #define cout(x) //cout<<x; for my applications. You may want to modify it like
#ifdef DEBUG
#define cout(x) cout<<x;
#else
#define cout(x)
And use it as
cout(arg0<<arg1<<arg2);
Here, you won't be commenting the line and thus won't need separate line for avoiding print.
Further you can use cout wherever printing has to be done unconditionally.
cout("Print this when debugging");
cout<<"Always print this";

C - How to use macro to leave out assert()'s in production release [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
my question might be partially related to When should we use asserts in C? But I'm still wondering which would be a better practice when I have a project with a bunch of assertions spread out at places:
Do I use the DNDEBUG flag to turn asserts into no-ops (as suggested in the related question), or do I surround all the asserts with a if macro like
#ifdef TEST
#include <assert.h>
#endif
....
#ifdef TEST
assert(...);
#endif
....
and use a -D TEST option at compliation time? Is there some sort of standard or 'convention' on this? I feel like the latter would be neater..
Thanks!
Is there some sort of standard or 'convention' on this?
Yes: define NDEBUG in production code. It's the ISO C standard way of doing this and only adds a few milliseconds to your compile cycle (or saves some compared to not defining NDEBUG, as you're including it anyway) because the compiler/preprocessor has to scan through <assert.h> to find out it has to remove things from your code. It doesn't bloat your executable or add any other kind of runtime overhead, unless you do crazy things in a #ifndef NDEBUG block.
Here is how I do this. Discussion below the code.
In some .h file:
#define PASS ((void)0)
extern void hook(void);
extern void asserthook(void);
#ifdef DEBUG
#define ENABLE_ASSERTS
#endif // DEBUG
#ifdef ENABLE_ASSERTS
#define AssertMesg(expr, mesg) \
do { \
if (!(expr)) \
{ \
asserthook(); \
fprintf(streamErr, \
"%s(%d): assertion failed: ", __FILE__, __LINE__); \
fprintf(streamErr, "%s\n", mesg); \
fflush(streamErr); \
Exit(10); \
} \
} while (0)
#define Assert(expr) AssertMesg(expr, "")
#else // !ENABLE_ASSERTS
#define AssertMesg(expr, mesg) PASS
#define Assert(expr) PASS
#endif // !ENABLE_ASSERTS
And in some .c file:
void hook(void)
{
PASS;
}
void asserthook(void)
{
hook();
}
First of all, my asserts always call asserthook() which calls hook(). These functions are just places to set a breakpoint; I also have errhook() that is called for an error. Usually I just set a breakpoint on hook() itself, and then anytime my code is taken down by an assert, I have the debugger stopped right on the error with the stack backtrace in just the spot I need.
When you are trying to make a multiline macro that will act like a C statement, the usual way to do it is to put it in curly braces and then wrap those braces in do / while (0). That's a loop that executes a single time, so it's really not a loop. But wrapping it like that means it is a statement and when you put a semi-colon on the line to terminate the statement, it's actually correct. Thus code like this will compile without errors and do the right thing:
if (error)
AssertMesg(0, "we have an error here");
else
printf("We don't have an error after all.\n");
If you didn't do the silly do / while (0) wrapper, and just had the curly braces, the above code won't work! First, the compiler would wonder why you have a ; right after a curly brace and before an else; second, the else would associate with the hidden if inside the AssertMesg() macro, and the printf() would never be called. You could fix the latter problem with explicit curly braces but it is clearly better to set up your macro so that it works in all situations, and that is what the do / while (0) does for you.
(void)0 is my preferred do-nothing statement. You could just use do {} while (0) if you prefer, or anything else that has no side-effects and doesn't use any variables.
The worst thing about the do / while (0) trick is that you sometimes see error messages that are complaining about a do loop, and since it's hidden inside macros you need to remember what is really going on. But it's the best way I know to make multiline macros work correctly.
When possible, you should use static inline functions rather than macros. But macros are completely portable to even sucky lame C compilers, and you need to use a macro for an assert so you can have __FILE__ and __LINE__ expanded properly.
(You could write a varargs function that does the actual assert, and then just make a macro that expands to a single call to that function, as long as varargs work correctly on all the compilers you use. I think I could do that now, but I already have the multiline macro solution working and I haven't touched it in a long time.)

Why does #define INVALID_VALUE -999; give a syntax error when used?

I am trying to compare to a defined constants in C, and I have simplified my program to the following:
#include "stdio.h"
#include "stdlib.h"
#define INVALID_VALUE -999;
int main(void)
{
int test=0;
if(test==INVALID_VALUE) //The error line..
return INVALID_VALUE;
return 0;
}
And when I use gcc to compile, it gives out error "error: expected ‘)’ before ‘;’ token".
Is there any reason that this cannot be done?
Remove the semicolon from your INVALID_VALUE definition.
Macros are replaced lexically (character-by-character) with no understanding of the syntax around them. Your macro INVALID_VALUE is set to -999;, so your if line expands the macro to:
if (test==-999;)
which is invalid C syntax.
You need to remove the ; in #define INVALID_VALUE -999;. See the fixed code.
You could have worked towards this conclusion by understanding what the error message expected ‘)’ before ‘;’ token was telling you. It's telling you that it expected to find a ) before the ; token, but from inspecting the line alone you don't see a ;. So maybe there's one in the definition of INVALID_VALUE? Look up at #define INVALID_VALUE -999; and there it is! Think it should be there, but not sure? So let's try remove it and see if it works. Success!
This page goes and explains why you shouldn't conclude a #define with a semicolon, even if it is needed in the use of the macro. It's good to learn as much as possible from your mistake so that you don't make it again. Quote:
Macro definitions, regardless of
whether they expand to a single or
multiple statements should not
conclude with a semicolon. If
required, the semicolon should be
included following the macro
expansion. Inadvertently inserting a
semicolon at the end of the macro
definition can unexpectedly change the
control flow of the program.
Another way to avoid this problem is
to prefer inline or static functions
over function-like macros.
In general, the programmer should
ensure that there is no semicolon at
the end of a macro definition. The
responsibility for having a semicolon
where needed during the use of such a
macro should be delegated to the
person invoking the macro.
The C Preprocessor Macro Language is Distinct from C
The ; in the macro definition should be removed.
This is an understandable mistake. If C were designed today, the macro language might be more integrated with the rest of C.
But on 16-bit machines in the early 1970's when C was invented, it was unwise to write an overly complicated program. It would end up useless as there would be no memory remaining to actually run the big masterpiece program, and even simple programs ran slowly.
So C was split into a rather simple macro preprocessor that was, originally, a completely separate program, and the compiler proper. The preprocessor program made no attempt to parse C beyond understanding the lexical analysis model.
When 32-bit machines took over, the preprocessor was typically integrated into the parser, but naturally the language needed to remain the same.
The semi colon at the end of
#define INVALID_VALUE -999;
Classic.
You do not need a semicolon after defining something. #define is actually a macro, and it will do an inline expansion on compile.
Thus,
#define IDENTIFIER 10;
int j = IDENTIFIER;
will expand as:
int j = 10;;
Change macro
from:
#define INVALID_VALUE -999;
to
#define INVALID_VALUE -999
Bye

Resources