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've been seeing that expression for over 10 years now. I've been trying to think what it's good for. Since I see it mostly in #defines, I assume it's good for inner scope variable declaration and for using breaks (instead of gotos.)
Is it good for anything else? Do you use it?
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
....
It is a way to simplify error checking and avoid deep nested if's. For example:
do {
// do something
if (error) {
break;
}
// do something else
if (error) {
break;
}
// etc..
} while (0);
It helps to group multiple statements into a single one so that a function-like macro can actually be used as a function. Suppose you have:
#define FOO(n) foo(n);bar(n)
and you do:
void foobar(int n) {
if (n)
FOO(n);
}
then this expands to:
void foobar(int n) {
if (n)
foo(n);bar(n);
}
Notice that the second call bar(n) is not part of the if statement anymore.
Wrap both into do { } while(0), and you can also use the macro in an if statement.
It is interesting to note the following situation where the do {} while (0) loop won't work for you:
If you want a function-like macro that returns a value, then you will need a statement expression: ({stmt; stmt;}) instead of do {} while(0):
#include <stdio.h>
#define log_to_string1(str, fmt, arg...) \
do { \
sprintf(str, "%s: " fmt, "myprog", ##arg); \
} while (0)
#define log_to_string2(str, fmt, arg...) \
({ \
sprintf(str, "%s: " fmt, "myprog", ##arg); \
})
int main() {
char buf[1000];
int n = 0;
log_to_string1(buf, "%s\n", "No assignment, OK");
n += log_to_string1(buf + n, "%s\n", "NOT OK: gcc: error: expected expression before 'do'");
n += log_to_string2(buf + n, "%s\n", "This fixes it");
n += log_to_string2(buf + n, "%s\n", "Assignment worked!");
printf("%s", buf);
return 0;
}
Generically, do/while is good for any sort of loop construct where one must execute the loop at least once. It is possible to emulate this sort of looping through either a straight while or even a for loop, but often the result is a little less elegant. I'll admit that specific applications of this pattern are fairly rare, but they do exist. One which springs to mind is a menu-based console application:
do {
char c = read_input();
process_input(c);
} while (c != 'Q');
Related
This question already has answers here:
Why use apparently meaningless do-while and if-else statements in macros?
(9 answers)
Closed 9 years ago.
I have noticed a programming style in Embedded C, used for firmware programming:
#define WRITE_REGISTER(reg, value) \
do { \
write_to_register(reg, value); \
} while (0)
How does this do...while (0) help over:
#define WRITE_REGISTER(reg, value) write_to_register(reg, value)
As you can see here the do {} while(0) permits to avoid compilation errors or bad working when there are multiple lines in the macro and you try to call the macro in the same way as a c function (which is the way everyone does).
As an example (I report the one in the link here so you don't need to navigate the page)
#define DO_SOMETHING_HERE(_x) foo(_x); bar(_x);
if( condition )
DO_SOMETHING_HERE(_x);
else
...
will generate a compilation error because it will result in:
if( condition )
foo(_x); bar(_x);;
else
...
Using the do while everything will work fine, infact it will be:
#define DO_SOMETHING_HERE(_x) do{ foo(_x); bar(_x); }while(0)
if( condition )
do{ foo(_x); bar(_x); } while(0);
else
...
Note that in this case putting braces will not save you because:
#define DO_SOMETHING_HERE(_x) { foo(_x); bar(_x); }
if( condition )
{ foo(_x); bar(_x); };
else
...
still generates an error.
In your case I think it's only a coding style because there's one line only.
With this kind of loop definition, you can use break statements within. This allows easier error handling. Example:
do
{
/* A lot of code */
if(error)
break;
/* A lot of code */
{
while(0)
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.
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?
When one needs to execute multiple statements within preprocessor macro, it's usually written like
#define X(a) do { f1(a); f2(a); } while(0)
so when this macro is used inside expressions like:
if (...)
X(a);
it would not be messed up.
The question is: wherever I've seen such expression, it's always do { ... } while(0);. Is there any reason to prefer such notion over (in my opinion more clear one) if (1) { ... }? Or am I wrong in my observations and they are equally popular?
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.
if can be as safe as do/while only if there is else branch. E.g.:
#define X(a) if(1) { f1(a); f2(a); } else{}
Is as safe as:
#define X(a) do { f1(a); f2(a); } while(0)
So that the user can't do:
X(...) else ...;
One difference is that when using do/while it requires a ; at the end, whereas if/else doesn't.
Consider this:
if(foo)
X(a);
else
whatever();
This would expand to:
if(foo)
if(1) { ... }
else
whatever();
Which is bad because now the else belongs to the wrong if.
Using do... while allows you to break out if necessary.
When you use #define X(a) do { ... } while(0) form, it forces you to put ; at the end of the statement X(1).
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).
I'm trying to write some microcontroller code using Texas Instruments examples, and it uses macros everywhere (probably to reduce code size), some of which are surrounded by st(). After reading the comments, I still don't understand why this is necessary or when I should use it:
/*
* This macro is for use by other macros to form a fully valid C statement.
* Without this, the if/else conditionals could show unexpected behavior.
*
* For example, use...
* #define SET_REGS() st( ioreg1 = 0; ioreg2 = 0; )
* instead of ...
* #define SET_REGS() { ioreg1 = 0; ioreg2 = 0; }
* or
* #define SET_REGS() ioreg1 = 0; ioreg2 = 0;
* The last macro would not behave as expected in the if/else construct.
* The second to last macro will cause a compiler error in certain uses
* of if/else construct
*
* It is not necessary, or recommended, to use this macro where there is
* already a valid C statement. For example, the following is redundant...
* #define CALL_FUNC() st( func(); )
* This should simply be...
* #define CALL_FUNC() func()
*
* (The while condition below evaluates false without generating a
* constant-controlling-loop type of warning on most compilers.)
*/
#define st(x) do { x } while (__LINE__ == -1)
Can you give some examples of what would fail when the st is not there? Is there any harm in adding the st where it's not necessary?
What might st stand for? When does the second example with { something } produce compiler errors? Because that's used in some example code, too.
The "do {...} while (0)" is a technique used to avoid some types of problems.
The __LINE__ == -1 probably was used to avoid some compiler warning. __LINE__ == -1 will always be false.
Take a look at this link and it will explain the reason for the "do... while(0)"
http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
Example:
#define a(x) if(x) { printf("%s\n", "OK"); }
int i = 1;
if(0)
a(i);
else
printf("%s\n", "KO");
Will expand to something equivalent to:
if(0)
{
if(x)
{
printf("%s\n", "OK");
}
else printf("%s\n", "KO");
}
However if you define a(x) as:
#define a(x) st(if(x) { printf("%s\n", "OK"); })
it will work, expanding to:
if(0)
{
do
{
if(x)
{
printf("%s\n", "OK");
}
}
while(0);
}
else printf("%s\n", "KO");