Purpose of #define foo() do { } while (0) - c

While browsing sources of LinCAN driver, I found some macros that baffled me.
#else /*CONFIG_PREEMPT*/
#define can_preempt_disable() do { } while (0)
#define can_preempt_enable() do { } while (0)
#endif /*CONFIG_PREEMPT*/
I understand the usefulness of
do {
...;
if(condition) break;
...
} while (0);
using break as a kind of throw. I semi-understand wrapping a sequence of functions like
#define FOO() do { foo(); bar(); } while (0)
to avoid caveats with braceless if. I understand sometimes "no-op statements" are required for a #define. But why this particular kind? specifically, empty braces, false condition, do...while? Some syntax caveats I can't quite grasp?

It is a common syntax for notifying the compiler that macro should be treated as a statement instead of as an expression (statements vs expressions).
In this case compiler will alert you if you try to use can_preempt_disable() as an expression. This means that we forced compile-time check that can_preempt_disable() is used as a statement. Compile-time checks are very often desirable.

The complete passage from the relevant file is:
#if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) ||
(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) )
#define can_preempt_disable preempt_disable
#define can_preempt_enable preempt_enable
#else /*CONFIG_PREEMPT*/
#define can_preempt_disable() do { } while (0)
#define can_preempt_enable() do { } while (0)
#endif /*CONFIG_PREEMPT*/
Thus, the first part is the code you get when you've asked for pre-emption protection, otherwise you get the empty, do-nothing, loops.
I guess they're written like that for the usual reasons, i.e. to ensure that the macro still is a valid statement.
There shouldn't be a terminating semicolon in the definition, since that will be in the code using these, such as this function which begins:
int c_can_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
{
can_preempt_disable();
...
So, clearly the macro is used like any other function call, and the semicolon is right there where the macro is invoked. This is very normal.
UPDATE 2: Defining it to a ; leads to double semicolons which is ugly, at least in my opinion. An empty brace pair {} would work I guess, but this do/while construct is even more idiomatic since it's often used in cases like these.
UPDATE 3: As pointed out in a comment, an empty brace pair won't work since then you can't put a semicolon after the call. Aah. Thanks!

Related

Linux Kernel defines everywhere

On linux's kernel we can find this piece of code in linux/sched.h, when I saw it some doubts came to my mind:
Why using define to create functions? Why not using the normal return-type function-name(par1, par2) {} style?
What is the point with the do {} while(0)?
#define set_special_state(state_value)
do {
unsigned long flags;
raw_spin_lock_irqsave(&current->pi_lock, flags);
current->state = (state_value);
raw_spin_unlock_irqrestore(&current->pi_lock, flags);
} while (0)
#endif
This isn't a "function", it's a preprocessor macro.
Sometimes one must use macros to do things that the C language itself doesn't support (usually generating code). This doesn't look like one of those cases though, and should probably be a static inline function. Pergaps the Git history would explain why it is the way it is.
do { ... } while (0) is a common method for swallowing the semicolon which follows a call to a C-function-looking macro like this one.
Functions are usually preferrable because they provide type checking and aren't error prone to things like double evaluation, but macros are more powerful, since they allow you to work at the text/token level.
do{}while(0) is to make an invoked macro grammatically behave like a void-returning function call.
You might think a plain pair of curlies would do that but that doesn't work
with if-else
#define macro_with_curlies() { }
if(x) macro_with_curlies(); else { }
//expands to: if(x) { }; /*else is illegal after the semicolon*/ else { }

How do I write if conditions like these in a macro?

I'm quite new to macros.
I know how to use if condition using ternary operator.
How do I convert this into a #define
if(i==j)
{
count=count+1;
break;
}
I try my luck with this but seems like it is wrong:
#define ifcount(i,j) ((i)==(j)? count=count+1\
break:0)
This is the code i'm trying to convert
http://pastebin.com/i7Tuyh00
Using (abusing) macros to change the flow of the program is usually a bad idea, because the people that will read your code (yourself in a few years) may get surprised by unexpected jumps in the program flow.
That said, your problem has nothing to do with the ternary operator. Actually the ternary operator cannot contain a break in its right side, only expressions.
But macros are allmighty, so you can just do:
#define ifcount(i,j) if ((i)==(j)) { count=count+1; break; }
The main problem with this macro is that people will write a ; when using it, and it will break badly if it is used between another if /else pair, without braces:
if (...)
ifcount(a,b);
else // <--- syntax error because the previous ; breaks the if /else relation
...;
The standard solution is to use the do/while(0) idiom:
#define do { ifcount(i,j) if ((i)==(j)) { count=count+1; break; } } while (0)
But that will not work because the break will break this inner while, not the one you want (credit to #abelenky) below.
The only other C statement that allows a compound statement and ends with a ; is this one:
#define ifcount(i,j) if ((i)==(j)) { count=count+1; break; } else
The problem is that if you forget to add the ; when using ifcount(i,j), instead of a compiler error you will get a silently compiling and surprisingly change in behavior.
I don't see any need to use the ternary (?:) operator.
So here is your macro using an if-statement.
#define IfCount(i,j) if ((i)==(j)) { count++; break; }
Usage:
IfCount(x,5);
Okay, what do you guys think of this?
#define IfCount(i,j) if ((i)==(j)) { count++; break; } do{}while(0)
The final, isolated do-while-0 serves a couple of purposes:
Its a place to hang a semi-colon, so the macro usage looks like "normal" C and ends with a semi-colon.
It prevents an inadvertent else-statement afterwards, because the syntax do{}while(0) else is invalid.
Is there anything else it should take care of?

Practical differences between "do {...} while (0)" and "{...} ((void)0)" in macros?

It's common practice in C to use:
#define FOO() do { /* body */ } while (0)
While this is fine, it's also possible to do:
#define FOO() { /* body */ }((void)0)
{...}((void)0) has many of the same benefits: you can't accidentally merge logic, and a ; is required at the end of the line, so odd expressions like this don't go by un-noticed: FOO() else {...}.
The only difference I've noticed is it means you need to use braces in if-statements.
if (a)
FOO();
else
BAR();
Must be written as:
if (a) {
FOO();
} else {
BAR();
}
Other then this quirk, it seems to work well, preventing the same kinds of problems do/while method is typically used for.
Are there any significant differences between the 2 methods?
Said differently, if you see a code-base using {...}((void)0), are practical reasons to switch to using do{..}while(0), besides the one difference already noted?
The practical difference is exactly what you pointed out.
The do { ... } while (0) idiom means that the macro can be used in any context that requires a statement.
Your suggested idiom { ... } ((void)0) can be used safely in most contexts that require an expression -- but it can fail if it's used in an unbraced if statement.
I can think of no good reason to use an unfamiliar idiom that almost always works, when there's a well known idiom that always works.
One difference is you can use break with #define FOO() do { /* body */ } while (0) but not with #define FOO() { /* body */ }(void)0.
Let's say you are inside a function, say hello(), and doing something in #define FOO() do { /*some device operation */ } while (0) but some error occurred so you no longer want to proceed with that device but there are other statements in function hello() you want to execute, let's say for another device.
So if you use second statement then you will do return most probably which will exit out of hello() but if you use the first statement you can happily break and do some operation in same function hello() for another device.

Is it OK to use a code block as an argument for a C macro?

I have a pattern that is basically some boilerplate code with a part that varies in the middle
if(condition){
struct Foo m = start_stuff();
{ m.foo = bar(1,2); m.baz = 17; } //this part varies
end_stuff();
}
Is it OK to make a macro taht takes that intermediate code block as an argument? The rules for macro expansion in C seem awfully complicated so I am not sure if there aren't any corner cases that could come and bite me in the future (in particular, I don't understand how the macro arguments are separated if my code has commas in it).
#define MY_MACRO(typ, do_stuff) do { \
if(condition){ \
struct typ m = start_stuff(); \
do_stuff; \
end_stuff(); \
} \
}while(0)
//usage
MY_MACRO(Foo, {
m.foo = bar(1,2);
m.baz = 17;
});
So far the only thing that I managed to think of is break and continue getting captured if I use looping statements in my macro and that would be an acceptable tradeoff for my particular use case.
edit: Of course, I would have used a functions if I could. The example I used in this question is simplified and doesn't showcase the bits that can only work with macro magic.
You can put a code block into a macro argument provided that it has no unguarded comma. In your example, the only comma in the argument is guarded because it is surrounded by parentheses.
Note that only parentheses guard commas. Brackets ([]) and braces ({}) do not. (And neither do angle brackets (<>) as noted in a comment.)
However, if the code block argument is the macro's last argument, you can use a variadic macro to increase flexibility. But beware: the increased flexibility also means that errors might go unnoticed. If you do this, you'll only have to make sure that the parentheses are balanced. (Again, only parentheses matter to the macro processor.)
As an alternative, you could consider using a macro that precedes your compound statement, as illustrated below. One of the pros of this is that all debuggers would still be able to step inside your compound statement, which is not the case with the compound-statement-as-macro-argument method.
//usage
MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}
Using some goto magic (yes, 'goto' may be evil in some cases, but we have few alternatives in C), the macro can be implemented as:
#define CAT(prefix, suffix) prefix ## suffix
#define _UNIQUE_LABEL(prefix, suffix) CAT(prefix, suffix)
#define UNIQUE_LABEL(prefix) _UNIQUE_LABEL(prefix, __LINE__)
#define MY_MACRO(typ, condition) if (condition) { \
struct typ m = start_stuff(); goto UNIQUE_LABEL(enter);} \
if (condition) while(1) if (1) {end_stuff(); break;} \
else UNIQUE_LABEL(enter):
Note that this has a small performance and footprint impact when compiler optimization is disabled. Also, a debugger will seem jump back to the MY_MACRO line when running calling the end_stuff() function, which is not really desirable.
Also, you might want to use the macro inside a new block scope to avoid pollution your scope with the 'm' variable:
{MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}}
Of course, using 'break' not inside a nested loop in the compound statement would skip the 'end_stuff()'. To allow for those to break the surrounding loop and still call 'end_stuff()', I think you'd have to enclose the compound statement with a start token and an end token as in:
#define MY_MACRO_START(typ, condition) if (condition) { \
struct typ m = start_stuff(); do {
#define MY_MACRO_EXIT goto UNIQUE_LABEL(done);} while (0); \
end_stuff(); break; \
UNIQUE_LABEL(done): end_stuff();}
MY_MACRO_START(foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
} MY_MACRO_END
Note that because of the 'break' in that approach, the MY_MACRO_EXIT macro would only be usable inside a loop or switch. You could use a simpler implementation when not inside a loop:
#define MY_MACRO_EXIT_NOLOOP } while (0); end_stuff();}
I used 'condition' as a macro argument, but you may also embed it directly in the macro if desired.
You can put code block into a macro but you must be warned that it makes debugging a lot harder using a debugger. IMHO is better just to either write a function or cut'n'paste the lines of code.
How about function pointers instead (and optionally inline functions)?
void do_stuff_inner_alpha(struct Foo *m)
{
m->foo = bar(1,2); m->baz = 17;
}
void do_stuff_inner_beta(struct Foo *m)
{
m->foo = bar(9, 13); m->baz = 445;
}
typedef void(*specific_modifier_t)(struct Foo *);
void do_stuff(specific_modifier_t func)
{
if (condition){
struct Foo m = start_stuff();
func(&m); //this part varies
end_stuff();
}
}
int main(int argc, const char *argv[])
{
do_stuff(do_stuff_inner_beta);
return EXIT_SUCCESS;
}
"Is it OK?" may mean two things:
Will it work? Here the answer is generally yes, but there are pitfalls. One, as rici mentioned, is an unguarded comma. Basically, remember that macro expansion is a copy&paste operation, and the preprocessor doesn't understand the code it copies and pastes.
Is it a good idea? I'd say the answer is generally no. It makes your code unreadable and hard to maintain. In some rare cases, this may be better than alternatives, if implemented well, but that's the exception.
Note that in C++ you could use a lambda the following way:
#include <iostream>
#define MY_MACRO(body) \
setup();\
body();\
teardown();\
int main() {
int a = 1;
MY_MACRO(([&]() mutable {
std::cout << "Look, no setup" << std::endl;
a++;
}));
std::cout << "a is now " << a << std::endl;
}
If you do this, you should first consider if there should instead be a function that plainly takes the lambda:
void withSetup(std::function<void ()> callback) {
setup();
callback();
teardown();
}
int main() {
withSetup([&]() {
doStuff();
});
}
Before answering your question "is it OK to use macro" I'd like to know why you want to convert that block of code to macro. What's that you're trying to gain and at what cost?
If same block of code you're using repeatedly, it's better to convert that in a function, maybe an inline function and leave it to compiler to make it inline or not.
Should you run into crash\issue, debugging a macro is a tedious task.

Why use do { } while (0) in macro definition? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
I met code like below:
#define ev_io_init(ev,cb,fd,events) \
do { \
ev_init ((ev), (cb)); \
ev_io_set ((ev),(fd),(events)); \
} while (0)
I want to know why the author use do { } while (0) here.
Is there any difference with this?
#define ev_io_init(ev,cb,fd,events) { \
ev_init ((ev), (cb)); \
ev_io_set ((ev),(fd),(events)); \
}
BTW: the code is from libev, ev_local.h
Consider if( something ) function1(); else function2();
If function1() is actually a macro, just using { } requires you to omit the semicolon at the point of use, but do { } while(0) lets you use exactly the same syntax as for a real function.
(Not using any kind of block construct at all would just generate completely broken code, natch)
Enclosing code with a loop allows for a preprocessor directive to execute multiple statements without "breaking" if-else-constructs. Consider the following:
#define DO_SOMETHING() a();b();c();
void foo()
{
// This is ok...
DO_SOMETHING();
}
void bar()
{
// ...whereas this would trigger an error.
if (condition)
DO_SOMETHING();
else
blah();
}
The second example breaks the if-else-construct because three statements are followed by an else clause. To allow for it to correctly substitute, the instructions in DO_SOMETHING should be enclosed with a do { ... } while(0).
A do{}while(0) allows you to break from the loop:
do{
expr1;
foo();
if ( cond )
break;
expr2;
goo();
} while (0);
It's the same as a simple block {...} except that you can break execution when you want with the break statement. You couldn't do that in a simple code block, unless you have multiple checks, which can get cumbersome. It still gets executed once, because of the condition while(0).

Resources