What's This C++ Syntax That Puts a Brace-Surrounded Block Where an Expression Is Expected

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



Leave a reply



Submit