| Why do I get the message "invalid lvalue in unary '&'"?

Previous | The C Language | Next

Q: | Well, I need to know more about lvalues and GNU C initializers and cast constructors. Especially, I need to know why I sometimes get an error message "invalid lvalue in unary '&'"...
A: | Click here to see everything about GNU C extensions. But if you are lazy to read too much, I will be more concrete here. First, in GNU C (TIGCC is GNU C), initializers may be non-constants. For example,
    int a = 3, b = 4, c = 5, d = 6;
    int array[4] = {a, b, c, d};
is quite legal. That's why
    int a = 3, b = 4, c = 5, d = 6;
    SCR_RECT myScr = {{b + a, b - a, d + c, d - c}};
is quite legal too. Second, GNU C has one very nice extension in addition to ordinary C: cast constructors. This is a method for constructing structures, arrays, unions etc. "on fly" by using a typecasting of an initializer to an appropriate data type, for example
    (SCR_RECT){{10, 10, 50, 50}}
So, you can use
    SCR_RECT myScr;
    ...
    myScr = (SCR_RECT){{10, 10, 50, 50}};
which is impossible in ordinary C (ANSI C). You can even use
    myScr = (SCR_RECT){{a, b, c, d}};
where a,b,c,d are expressions. Well, but what is now the problem? See, C has two type of objects: lvalues and non-lvalues. lvalues are objects which may appear on the left size of an assignment. For example, a variable is an lvalue and a constant is not an lvalue, because `'x=5'` is legal and `'5=x'` (or `'5=3'`) is not legal. Not only variables are lvalues; for example, dereferenced pointers are also lvalues, so this is legal for example (store 100 at address 0x4c00):
    *(char*)0x4c00 = 100;
So, `'*(char*)0x4c00'` is an lvalue. Now, about the problem. In GNU C, cast constructors are lvalues only if the initializer is completely constant. I.e. `'(SCR_RECT){{10,10,50,50}}'` is an lvalue, but `'(SCR_RECT){{a,b,c,d}}'` is not. As C language accepts unary '&' operator (i.e. "address of") only on lvalue objects, this means that, for example,
    &(SCR_RECT){{10, 10, 50, 50}}
is legal, but
    &(SCR_RECT){{a, b, c, d}}
is not! This is the real cause of the problem!!! What you can do if you need an address of non-constant cast constructor? You need to declare an auxilary variable. For example, declare one SCR_RECT variable, say myScr,
    SCR_RECT myScr;
and instead of
    ScrRectFill (&(SCR_RECT){{a, b, c, d}}, ScrRect, A_XOR);
use:
    myScr = (SCR_RECT){{a, b, c, d}};
    ScrRectFill (&myScr, ScrRect, A_XOR);
Note that `'&myScr'` is legal, because `'myScr'` is an lvalue (it is an ordinary variable). I hope that this helps a lot understanding of cast constructors and lvalues.