I was looking at the Linux source and the following line seemed strange.
What may be the use of the (void) ( { .... ;} ) construct?
#define GETCH(queue,c) \
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
Here is what I think:
1. (void) suppresses some compiler warnings.
2. {....} is there to group the two statements together, so that it can use used like while(...) GETCH(q,c); correctly.
Is there any other reason? Is there any documentation available?
Source: Linux-0.01 Source - GitHub
In this macro, the author uses a GCC “statement expression” extension to do two things:
Supply two statements, an assignment (c=…) and a use of the INC macro, which I presume performs some increment to its argument.
Package those two statements so that, when followed by a semicolon, they form a single statement.
The reason for the latter to allow this macro to be used in places like this:
if (some expression)
GETCH(queue,c);
else
some other statement;
For example, suppose the macro had been written using normal braces, like this:
#define GETCH(queue,c) \
{c=(queue).buf[(queue).tail];INC((queue).tail);}
Then it would supply both statements and group them, so we could use them in simple code like this:
statement X;
GETCH(queue,c);
statement Y;
However, consider the consequences in the if statement. We would have
if (some expression)
{c=(queue).buf[(queue).tail];INC((queue).tail);};
else
some other statement;
There is a problem: { … } and ; are two statements. The ; is an empty expression statement. And you cannot have two statements between an if and an else. The compiler will emit a warning when it sees the else after the two statements. But the author of GETCH wanted you to be able to use the macro followed by a semicolon as one statement—they wanted it to “look like” a function call, which you can follow with a semicolon.
So, the author did something else. They used a feature of GCC called a statement expression. It is not a part of the C standard; it is an extension defined by GCC. When using GCC, a compound statement (a statement in braces, { … }) that ends with an expression statement and is enclosed in parentheses (({ … })) acts like an expression whose value is the last expression statement inside the braces. For example ({ if (x) z=x*x; else z=5; 3*z; }) acts like an expression with the value 3*z, in addition to perform the statements inside the braces. Because this is a single expression, you can follow it with a semicolon to form a single statement.
So, if the author had written:
#define GETCH(queue,c) \
({c=(queue).buf[(queue).tail];INC((queue).tail);})
then we could write:
if (some expression)
GETCH(queue,c);
else
some other statement;
The author also included a cast to (void):
#define GETCH(queue,c) \
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
I expect the purpose of that is to prevent the expression statement from being used as an expression—the author only wanted it to act in the grammar as a single statement and did not want its resulting value used.
That said, I do not see why the author chose to use a GCC extension for this. There is a well known way of doing this in standard C:
#define GETCH(queue,c) \
do {c=(queue).buf[(queue).tail];INC((queue).tail);} while (0)
The statement inside the do will be executed just once (because it is executed first, then the while expression is checked, and it is false, so no loop occurs), and following the above with a semicolon forms a single statement.
Related
Pardon if this question is naive. Consider the following program:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
In the above example, the statements 5; and i; seem totally superfluous, yet the code compiles without warnings or errors by default (however, gcc does throw a warning: statement with no effect [-Wunused-value] warning when ran with -Wall). They have no effect on the rest of the program, so why are they considered valid statements in the first place? Does the compiler simply ignore them? Are there any benefits to allowing such statements?
One benefit to allowing such statements is from code that's created by macros or other programs, rather than being written by humans.
As an example, imagine a function int do_stuff(void) that is supposed to return 0 on success or -1 on failure. It could be that support for "stuff" is optional, and so you could have a header file that does
#if STUFF_SUPPORTED
#define do_stuff() really_do_stuff()
#else
#define do_stuff() (-1)
#endif
Now imagine some code that wants to do stuff if possible, but may or may not really care whether it succeeds or fails:
void func1(void) {
if (do_stuff() == -1) {
printf("stuff did not work\n");
}
}
void func2(void) {
do_stuff(); // don't care if it works or not
more_stuff();
}
When STUFF_SUPPORTED is 0, the preprocessor will expand the call in func2 to a statement that just reads
(-1);
and so the compiler pass will see just the sort of "superfluous" statement that seems to bother you. Yet what else can one do? If you #define do_stuff() // nothing, then the code in func1 will break. (And you'll still have an empty statement in func2 that just reads ;, which is perhaps even more superfluous.) On the other hand, if you have to actually define a do_stuff() function that returns -1, you may incur the cost of a function call for no good reason.
Simple Statements in C are terminated by semicolon.
Simple Statements in C are expressions. An expression is a combination of variables, constants and operators. Every expression results in some value of a certain type that can be assigned to a variable.
Having said that some "smart compilers" might discard 5; and i; statements.
Statements with no effect are permitted because it would be more difficult to ban them than to permit them. This was more relevant when C was first designed and compilers were smaller and simpler.
An expression statement consists of an expression followed by a semicolon. Its behavior is to evaluate the expression and discard the result (if any). Normally the purpose is that the evaluation of the expression has side effects, but it's not always easy or even possible to determine whether a given expression has side effects.
For example, a function call is an expression, so a function call followed by a semicolon is a statement. Does this statement have any side effects?
some_function();
It's impossible to tell without seeing the implementation of some_function.
How about this?
obj;
Probably not -- but if obj is defined as volatile, then it does.
Permitting any expression to be made into an expression-statement by adding a semicolon makes the language definition simpler. Requiring the expression to have side effects would add complexity to the language definition and to the compiler. C is built on a consistent set of rules (function calls are expressions, assignments are expressions, an expression followed by a semicolon is a statement) and lets programmers do what they want without preventing them from doing things that may or may not make sense.
The statements you listed with no effect are examples of an expression statement, whose syntax is given in section 6.8.3p1 of the C standard as follows:
expression-statement:
expressionopt ;
All of section 6.5 is dedicated to the definition of an expression, but loosely speaking an expression consists of constants and identifiers linked with operators. Notably, an expression may or may not contain an assignment operator and it may or may not contain a function call.
So any expression followed by a semicolon qualifies as an expression statement. In fact, each of these lines from your code is an example of an expression statement:
i = i + 2;
5;
i;
printf("i: %d\n", i);
Some operators contain side effects such as the set of assignment operators and the pre/post increment/decrement operators, and the function call operator () may have a side effect depending on what the function in question does. There is no requirement however that one of the operators must have a side effect.
Here's another example:
atoi("1");
This is calling a function and discarding the result, just like the call printf in your example but the unlike printf the function call itself does not have a side effect.
Sometimes such a statements are very handy:
int foo(int x, int y, int z)
{
(void)y; //prevents warning
(void)z;
return x*x;
}
Or when reference manual tells us to just read the registers to archive something - for example to clear or set some flag (very common situation in the uC world)
#define SREG ((volatile uint32_t *)0x4000000)
#define DREG ((volatile uint32_t *)0x4004000)
void readSREG(void)
{
*SREG; //we read it here
*DREG; // and here
}
https://godbolt.org/z/6wjh_5
This question already has answers here:
Closed 13 years ago.
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?
do { … } while (0) what is it good for?
I've seen some multi-line C macros that are wrapped inside a do/while(0) loop like:
#define FOO \
do { \
do_stuff_here \
do_more_stuff \
} while (0)
What are the benefits (if any) of writing the code that way as opposed to using a basic block:
#define FOO \
{ \
do_stuff_here \
do_more_stuff \
}
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 and bar are ordinary functions. Now imagine that you'd
like to replace function foo with a macro of the above nature [named CALL_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 of if is now represented by a compound statement. And when you
put a ; after this compound statement, you finished the whole if
statement, thus orphaning the else 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
of CALL_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 ; after while (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).
Often, in macros, you will see people use a do { ... } while(0) to swallow the semicolon. I just came across an example where they use ({ ... }) instead, and it seems to not only swallow the semicolon, but seems to allow you to return a value as well:
#define NEW_MACRO() ({ int x = 1; int y = 2; x+y; })
if(1)
val = NEW_MACRO();
else
printf("this never prints");`
val would come out being 3. I can't find any documentation on it, so I'm a bit wary of it. Are there any gotcha's with this method?
This is not valid in standard C.
Some compilers may have extensions (e.g. GCC's statement expressions) that allow this sort of thing.
As Oli said correctly this was invented by gcc. The goal is (often with their typeof extension) to be able to evaluated macro elements only once and use this computed value later on by using a name.
Many times such a use can be completely avoided by using inline functions. These also have the (dis)advantage of being more strict on types.
In some other cases where you just need a temporary variable whose address you pass to a function, C99 also has compound literals that can be used for this.
do { ... } while(0) is not for the "swallowing the semicolon". It is for turning the C expression to the C statement.
This question already has answers here:
Closed 12 years ago.
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)
* - setting 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.
This question already has answers here:
Closed 13 years ago.
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?
do { … } while (0) what is it good for?
I've seen some multi-line C macros that are wrapped inside a do/while(0) loop like:
#define FOO \
do { \
do_stuff_here \
do_more_stuff \
} while (0)
What are the benefits (if any) of writing the code that way as opposed to using a basic block:
#define FOO \
{ \
do_stuff_here \
do_more_stuff \
}
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 and bar are ordinary functions. Now imagine that you'd
like to replace function foo with a macro of the above nature [named CALL_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 of if is now represented by a compound statement. And when you
put a ; after this compound statement, you finished the whole if
statement, thus orphaning the else 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
of CALL_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 ; after while (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).