| 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.