What's this C++ syntax that puts a brace-surrounded block where an expression is expected?
It assigns user input value to a
and prints it out. it is done by using a Statement Expression
.
Statement Expressions are a gnu gcc compiler extension and are not supported by the C/C++ standards. Hence, any code which uses statement expression is not standard conforming and non-portable.
The IBM XL C/C++ v7.0 also support Statement Expressions & its documentation explains them aptly:
Statement Expressions:
A compound statement is a sequence of statements enclosed by braces. In GNU C, a compound statement inside parentheses may appear as an expression in what is called a
Statement expression
.
.--------------.
V |
>>-(--{----statement--;-+--}--)--------------------------------><
The value of a statement expression is the value of the last simple expression to appear in the entire construct. If the last statement is not an expression, then the construct is of type void and has no value.
Always compile your code by selecting a standard in GCC: use one of the options -ansi
, -std=c90
or -std=iso9899:1990
, -std=c++03
, -std=c++0x
; to obtain all the diagnostics required by the standard, you should also specify -pedantic
(or -pedantic-errors
if you want them to be errors rather than warnings).
Advanced C question: Please explain C construct *({ foo(&bar); &bar; })
The syntax of statements within a ({ ... })
block is a statement expression which is a GCC extension. It allows you to run a series of statements where the last statement in the block is an expression which becomes the value of the full statement expression. So in this case the statement expression has the value &work
.
Since the statement expression evaluates to &work
, the *
right before the statement expression gives you *&work
, or equivalently work
as the value of the macro COMPLETION_INITIALIZER_ONSTACK
.
Now let's look at DECLARE_COMPLETION_ONSTACK
. When it is used:
DECLARE_COMPLETION_ON_STACK(comp);
It expands to:
struct completion comp= COMPLETION_INITIALIZER_ONSTACK(comp);
Which further expands to:
struct completion comp = (*({ init_completion(&comp ); ∁ }))
Breaking this down, the variable comp
is being initialized with a statement expression. The first statement in that expression is a call to the function init_completion
which is passed the address of the new variable. This function sets the values of the variable which at this point hasn't actually been initialized yet. The next (and last) statement in the statement expression is &comp
which is the value of the statement expression. This address is then dereferenced giving us comp
which is then assigned to comp
. So the variable is being validly initialized with itself!
Normally initializing a variable with itself would invoke undefined behavior because you would be trying to read an uninitialized variable, but not in this case because the variable's address is passed to a function which assigns values to its fields before it's initialized.
You might ask why COMPLETION_INITIALIZER_ONSTACK
was not defined like this:
#define COMPLETION_INITIALIZER_ONSTACK(work) \
({ init_completion(&work); work; })
If done this way, a temporary variable is created on the stack. Using the addrress prevents this from happening. In fact the code originally did this but was changed to what you see in the following commit:
https://github.com/torvalds/linux/commit/ec81048cc340bb03334e6ca62661ecc0a684897a#diff-f4f6d7a50d07f6f07835787ec35565bb
Strange C/C++ syntax
They're called statement expressions, it's a GNU extension. In your example the result of the expression is b__
.
do while loop without {}
The original resource to answer this question should be the C++ standards: http://www.open-std.org/jtc1/sc22/wg21/docs/standards.
In C++17, 9.5 Iteration statements [stmt.iter] says do
takes a statement:
do statement while ( expression ) ;
So this is definitely fine.
9.3 Compound statement or block [stmt.block] says
So that several statements can be used where one is expected, the compound statement (also, and equivalently,
called “block”) is provided.
so people tend/like to use { ... }
for do
statements.
Anonymous code blocks in c
It is an Statement Expression.
It as an compiler extension supported by GCC and it is not Standard C++,hence it is non portable.
If you compile your code with the -pedantic
flag it will tell you so.
This answer of mine talks about it in detail.
Related Topics
How to Avoid the Diamond of Death When Using Multiple Inheritance
Spiral Rule and 'Declaration Follows Usage' for Parsing C and C++ Declarations
How to 'Cout' the Correct Number of Decimal Places of a Double Value
When and How to Use Exception Handling
C++ Equivalent to Java's Blockingqueue
When Is Overloading Pass by Reference (L-Value and R-Value) Preferred to Pass-By-Value
Measure Execution Time in C++ Openmp Code
What's the Behavior of an Uninitialized Variable Used as Its Own Initializer
Choosing Between Std::Map and Std::Unordered_Map
When Is It Necessary to Use the Flag -Stdlib=Libstdc++
Are Child Processes Created with Fork() Automatically Killed When the Parent Is Killed
Check Traits for All Variadic Template Arguments
Winapi Sleep() Function Call Sleeps for Longer Than Expected
How to Use Std::String in a Constexpr
How to Read File Content into Istringstream
Why C++ Copy Constructor Must Use Const Object