(gcc.info.gz) Statement Exprs

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