What does "do { ... } while (0)" do exactly in kernel code? [duplicate]
Possible Duplicates:
What’s the use of do while(0) when we define a macro? Why are there sometimes meaningless do/while and if/else statements in C/C++ macros? C multi-line macro: do/while(0) vs scope block
I have seen a lot of usages like this, previously I though that the programmer wanted to break out of a block of code easily. Why do we need a do { ... } while (0) loop here? Are we trying to tell the compiler something?
For instance in Linux kernel 2.6.25, include/asm-ia64/system.h
/*
* - clearing psr.i is implicitly serialized (visible by next insn)
* - set开发者_如何转开发ting psr.i requires data serialization
* - we need a stop-bit before reading PSR because we sometimes
* write a floating-point register right before reading the PSR
* and that writes to PSR.mfl
*/
#define __local_irq_save(x) \
do { \
ia64_stop(); \
(x) = ia64_getreg(_IA64_REG_PSR); \
ia64_stop(); \
ia64_rsm(IA64_PSR_I); \
} while (0)
It's always used in macros so that a semicolon is required after a call, just like when calling a regular function.
In your example, you have to write
__local_irq_save(1);
while
__local_irq_save(1)
would result in an error about a missing semicolon. This would not happen if the do while was not there. If it was just about scoping, a simple curly brace pair would suffice.
It allows for the code to appear here:
if(a) __local_irq_save(x); else ...;
// -> if(a) do { .. } while(0); else ...;
If they simply used a { .. }
you would get
if(a) { ... }; else ...;
The else would not belong to any if
anymore, because the semicolon would be the next statement and separate the else
from the preceeding if
. A compile error would occur.
The purpose of do{ ... } while(0)
construct is to turn a group of statements into a single compound statement that can be terminated with a ;
. You see, in C language the do/while
construct has one weird and unusual property: even though it "works" as a compound statement, it expects a ;
at the end. No other compound constructs in C have this property.
Because of this property, you can use do/while
to write multi-statement macros, which can be safely used as "ordinary" functions without worrying what's inside the macro, as in the following example
if (/* some condition */)
__local_irq_save(x); /* <- we can safely put `;` here */
else
/* whatever */;
The answer has already been given (so the macro forces a ;
when called), but another use of this kind of statement that I have seen: it allows break to be called anywhere in the "loop", early terminating if needed. Essentially a "goto" that your fellow programmers wouldn't murder you for.
do {
int i = do_something();
if(i == 0) { break; } // Skips the remainder of the logic
do_something_else();
} while(0);
Note that this is still fairly confusing, so I don't encourage its use.
Looks like it's there just for scoping. It's similar to:
if (true)
{
// Do stuff.
}
edit
I don't see it in your example, but it's possible that one of those function calls is actually a macro, in which case there's one key difference between do/while(0) and if(true), which is that the former allows continue
and break
.
It makes use of the macro act like a real statement or function call.
A statement is either { expression-list }
or expression;
so that poses a problem when defining macros that need more than one expression, because if you use { }
then a syntax error will occur if the caller of the macro quite reasonably adds a ;
before an else.
if(whatever)
f(x);
else
f(y);
If f()
is a single statement macro, fine, but what if it's a macro and something complicated? You end up with if(...) { s1; s2; }; else ...
and that doesn't work.
So the writer of the macro has to then either make it into a real function, wrap the construct in a single statement, or use a gnu extension.
The do .. while(0)
pattern is the "wrap the construct" approach.
精彩评论