Why use apparently meaningless do-while and if-else statements in macros?
The do ... while
and if ... else
are there to make it so that a
semicolon after your macro always means the same thing. Let's say you
had something like your second macro.
#define BAR(X) f(x); g(x)
Now if you were to use BAR(X);
in an if ... else
statement, where the bodies of the if statement were not wrapped in curly brackets, you'd get a bad surprise.
if (corge)
BAR(corge);
else
gralt();
The above code would expand into
if (corge)
f(corge); g(corge);
else
gralt();
which is syntactically incorrect, as the else is no longer associated with the if. It doesn't help to wrap things in curly braces within the macro, because a semicolon after the braces is syntactically incorrect.
if (corge)
{f(corge); g(corge);};
else
gralt();
There are two ways of fixing the problem. The first is to use a comma to sequence statements within the macro without robbing it of its ability to act like an expression.
#define BAR(X) f(X), g(X)
The above version of bar BAR
expands the above code into what follows, which is syntactically correct.
if (corge)
f(corge), g(corge);
else
gralt();
This doesn't work if instead of f(X)
you have a more complicated body of code that needs to go in its own block, say for example to declare local variables. In the most general case the solution is to use something like do ... while
to cause the macro to be a single statement that takes a semicolon without confusion.
#define BAR(X) do { \
int i = f(X); \
if (i > 4) g(i); \
} while (0)
You don't have to use do ... while
, you could cook up something with if ... else
as well, although when if ... else
expands inside of an if ... else
it leads to a "dangling else", which could make an existing dangling else problem even harder to find, as in the following code.
if (corge)
if (1) { f(corge); g(corge); } else;
else
gralt();
The point is to use up the semicolon in contexts where a dangling semicolon is erroneous. Of course, it could (and probably should) be argued at this point that it would be better to declare BAR
as an actual function, not a macro.
In summary, the do ... while
is there to work around the shortcomings of the C preprocessor. When those C style guides tell you to lay off the C preprocessor, this is the kind of thing they're worried about.
do { } while(0) vs. if (1) { } in macros [duplicate]
Nope, you're not wrong.
There's actually a nice reason:
#define my_code if (1) { ... }
if (1)
my_code;
The problem is with the ;
! It shouldn't be there... and that would just look strange and not in the spirit of the language. You can either choose to have a code that expands in to two ;
in a row, or a code that looks un-c-ish :)
On the other hand, the do-while
construction does not have that problem.
Also, as others mentioned, there's an else
problem:
if (1)
my_code;
else { ... }
Ignoring the ;
issuse, the else
block now belongs to the wrong if.
What's the use of do while(0) when we define a macro? [duplicate]
You can follow it with a semicolon and make it look and act more like a function.
It also works with if/else clauses properly then.
Without the while(0), your code above would not work with
if (doit)
INIT_LIST_HEAD(x);
else
displayError(x);
since the semicolon after the macro would "eat" the else clause, and the above wouldn't even compile.
Significance of do{} while(0) [duplicate]
It can be used to leave a certain scope of code at any point without leaving the function. Consider:
do
{
beginAtomicOperationSequence();
ret = doSomething();
if (ret < 0) break;
ret = doSomething2();
if (ret < 0) break;
} while(0);
if (ret < 0) {
switch (ret) {
//handle error
}
rollbackAboveOperations();
} else {
commitAboveOperations();
}
There are some cases in which I would say that this is acceptable, particularly if one needs to make a sequence of operations which are to be considered atomic. Like in the example above.
C multi-line macro: do/while(0) vs scope block [duplicate]
Andrey Tarasevich provides the following explanation:
- On Google Groups
- On bytes.com
[Minor changes to formatting made. Parenthetical annotations added in square brackets []
].
The whole idea of using 'do/while' version is to make a macro which will
expand into a regular statement, not into a compound statement. This is
done in order to make the use of function-style macros uniform with the
use of ordinary functions in all contexts.Consider the following code sketch:
if (<condition>)
foo(a);
else
bar(a);where
foo
andbar
are ordinary functions. Now imagine that you'd
like to replace functionfoo
with a macro of the above nature [namedCALL_FUNCS
]:if (<condition>)
CALL_FUNCS(a);
else
bar(a);Now, if your macro is defined in accordance with the second approach
(just{
and}
) the code will no longer compile, because the 'true'
branch ofif
is now represented by a compound statement. And when you
put a;
after this compound statement, you finished the wholeif
statement, thus orphaning theelse
branch (hence the compilation error).One way to correct this problem is to remember not to put
;
after
macro "invocations":if (<condition>)
CALL_FUNCS(a)
else
bar(a);This will compile and work as expected, but this is not uniform. The
more elegant solution is to make sure that macro expand into a regular
statement, not into a compound one. One way to achieve that is to define
the macro as follows:#define CALL_FUNCS(x) \
do { \
func1(x); \
func2(x); \
func3(x); \
} while (0)Now this code:
if (<condition>)
CALL_FUNCS(a);
else
bar(a);will compile without any problems.
However, note the small but important difference between my definition
ofCALL_FUNCS
and the first version in your message. I didn't put a;
after} while (0)
. Putting a;
at the end of that definition
would immediately defeat the entire point of using 'do/while' and make
that macro pretty much equivalent to the compound-statement version.I don't know why the author of the code you quoted in your original
message put this;
afterwhile (0)
. In this form both variants are
equivalent. The whole idea behind using 'do/while' version is not to
include this final;
into the macro (for the reasons that I explained
above).
do { ... } while (0) — what is it good for? [duplicate]
It's the only construct in C that you can use to #define
a multistatement operation, put a semicolon after, and still use within an if
statement. An example might help:
#define FOO(x) foo(x); bar(x)
if (condition)
FOO(x);
else // syntax error here
...;
Even using braces doesn't help:
#define FOO(x) { foo(x); bar(x); }
Using this in an if
statement would require that you omit the semicolon, which is counterintuitive:
if (condition)
FOO(x)
else
...
If you define FOO like this:
#define FOO(x) do { foo(x); bar(x); } while (0)
then the following is syntactically correct:
if (condition)
FOO(x);
else
....
In C macros, should one prefer do { ... } while(0,0) over do { ... } while(0)?
Well, I'll go for an answer:
Is there a legitimate reason why one should prefer the second form of the macro... ?
No. There is no legitimate reason. Both always evaluate to false, and any decent compiler will probably turn the second one into the first in the assembly anyway. If there was any reason for it to be invalid in some cases, C's been around far long enough for that reason to be discovered by greater gurus than I.
If you like your code making owl-y eyes at you, use while(0,0)
. Otherwise, use what the rest of the C programming world uses and tell your customer's static analysis tool to shove it.
Understanding macro code statement with lambda and __attribute__
do...while(0)
allows the macro to by called with semicolon at the end, i.e. macro(x,y,z);
(note the semicolon at the end), that's an old trick back from C, you can look it up separately.
As for the rest... it defines a lambda (immediate function object) capturing everything by reference (not sure why) that throws exception of a given type with a given message and calls it immediately, effectively throwing an exception.
The attributes signify the lambda is unlikely to be called (cold) and prevent from inlining (noinline), see: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
Related Topics
Invalid Operands Error for Addition and Integer Division
Difference Between Function Template and Template Function
Why Should I Always Enable Compiler Warnings
Boost Spirit: "Semantic Actions Are Evil"
Why Does Reading a Record Struct Fields from Std::Istream Fail, and How to Fix It
How to Convert an Instance of Std::String to Lower Case
How to Figure Out the Parameter Type and Return Type of a Lambda
Why Use Static_Cast≪Int≫(X) Instead of (Int)X
Why Is Address of Char Data Not Displayed
How to Align Text to the Right Using Cout
C++: How to Iterate Over Each Char in a String
Is There a Difference Between Copy Initialization and Direct Initialization
Single Quotes Vs. Double Quotes in C or C++
What Is the Proper Declaration of Main in C++