gcc: Statement Exprs

1 
1 6.1 Statements and Declarations in Expressions
1 ==============================================
1 
1 A compound statement enclosed in parentheses may appear as an expression
1 in GNU C.  This allows you to use loops, switches, and local variables
1 within an expression.
1 
1  Recall that a compound statement is a sequence of statements surrounded
1 by braces; in this construct, parentheses go around the braces.  For
1 example:
1 
1      ({ int y = foo (); int z;
1         if (y > 0) z = y;
1         else z = - y;
1         z; })
1 
1 is a valid (though slightly more complex than necessary) expression for
1 the absolute value of 'foo ()'.
1 
1  The last thing in the compound statement should be an expression
1 followed by a semicolon; the value of this subexpression serves as the
1 value of the entire construct.  (If you use some other kind of statement
1 last within the braces, the construct has type 'void', and thus
1 effectively no value.)
1 
1  This feature is especially useful in making macro definitions "safe"
1 (so that they evaluate each operand exactly once).  For example, the
1 "maximum" function is commonly defined as a macro in standard C as
1 follows:
1 
1      #define max(a,b) ((a) > (b) ? (a) : (b))
1 
1 But this definition computes either A or B twice, with bad results if
1 the operand has side effects.  In GNU C, if you know the type of the
1 operands (here taken as 'int'), you can define the macro safely as
1 follows:
1 
1      #define maxint(a,b) \
1        ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
1 
1  Embedded statements are not allowed in constant expressions, such as
1 the value of an enumeration constant, the width of a bit-field, or the
1 initial value of a static variable.
1 
1  If you don't know the type of the operand, you can still do this, but
1 you must use 'typeof' or '__auto_type' (⇒Typeof).
1 
1  In G++, the result value of a statement expression undergoes array and
1 function pointer decay, and is returned by value to the enclosing
1 expression.  For instance, if 'A' is a class, then
1 
1              A a;
1 
1              ({a;}).Foo ()
1 
1 constructs a temporary 'A' object to hold the result of the statement
1 expression, and that is used to invoke 'Foo'.  Therefore the 'this'
1 pointer observed by 'Foo' is not the address of 'a'.
1 
1  In a statement expression, any temporaries created within a statement
1 are destroyed at that statement's end.  This makes statement expressions
1 inside macros slightly different from function calls.  In the latter
1 case temporaries introduced during argument evaluation are destroyed at
1 the end of the statement that includes the function call.  In the
1 statement expression case they are destroyed during the statement
1 expression.  For instance,
1 
1      #define macro(a)  ({__typeof__(a) b = (a); b + 3; })
1      template<typename T> T function(T a) { T b = a; return b + 3; }
1 
1      void foo ()
1      {
1        macro (X ());
1        function (X ());
1      }
1 
1 has different places where temporaries are destroyed.  For the 'macro'
1 case, the temporary 'X' is destroyed just after the initialization of
1 'b'.  In the 'function' case that temporary is destroyed when the
1 function returns.
1 
1  These considerations mean that it is probably a bad idea to use
1 statement expressions of this form in header files that are designed to
1 work with C++.  (Note that some versions of the GNU C Library contained
1 header files using statement expressions that lead to precisely this
1 bug.)
1 
1  Jumping into a statement expression with 'goto' or using a 'switch'
1 statement outside the statement expression with a 'case' or 'default'
1 label inside the statement expression is not permitted.  Jumping into a
1 statement expression with a computed 'goto' (⇒Labels as Values)
1 has undefined behavior.  Jumping out of a statement expression is
1 permitted, but if the statement expression is part of a larger
1 expression then it is unspecified which other subexpressions of that
1 expression have been evaluated except where the language definition
1 requires certain subexpressions to be evaluated before or after the
1 statement expression.  In any case, as with a function call, the
1 evaluation of a statement expression is not interleaved with the
1 evaluation of other parts of the containing expression.  For example,
1 
1        foo (), (({ bar1 (); goto a; 0; }) + bar2 ()), baz();
1 
1 calls 'foo' and 'bar1' and does not call 'baz' but may or may not call
1 'bar2'.  If 'bar2' is called, it is called after 'foo' and before
1 'bar1'.
1