| Generalized Lvalues

Previous | GNU C Language Extensions | Next

Compound expressions, conditional expressions and casts are allowed as lvalues provided their operands are lvalues. This means that you can take their addresses or store values into them.
For example, a compound expression can be assigned, provided the last expression in the sequence is an lvalue. These two expressions are equivalent:

    (a, b) += 5
    a, (b += 5)

Similarly, the address of the compound expression can be taken. These two expressions are equivalent:

    &(a, b)
    a, &b

A conditional expression is a valid lvalue if its type is not void and the true and false branches are both valid lvalues. For example, these two expressions are equivalent:

    (a ? b : c) = 5
    (a ? b = 5 : (c = 5))

A cast is a valid lvalue if its operand is an lvalue. A simple assignment whose left-hand side is a cast works by converting the right-hand side first to the specified type, then to the type of the inner left-hand side expression. After this is stored, the value is converted back to the specified type to become the value of the assignment. Thus, if `a` has type `char*`, the following two expressions are equivalent:

    (int)a = 5
    (int)(a = (char *)(int)5)

An assignment-with-arithmetic operation such as `+=` applied to a cast performs the arithmetic using the type resulting from the cast, and then continues as in the previous case. Therefore, these two expressions are equivalent:

    (int)a += 5
    (int)(a = (char *)(int) ((int)a + 5))

You cannot take the address of an lvalue cast, because the use of its address would not work out coherently. Suppose that `&(int)f` were permitted, where `f` has type `float`. Then the following statement would try to store an integer bit-pattern where a floating point number belongs:

    *&(int)f = 1;

This is quite different from what `(int)f = 1` would do - that would convert 1 to floating point and store it. Rather than cause this inconsistency, the GNU team thinks it is better to prohibit use of `&` on a cast.
If you really do want an `int*` pointer with the address of `f`, you can simply write `(int*)&f`.