LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   lvalue required as left operand of assignment (https://www.linuxquestions.org/questions/programming-9/lvalue-required-as-left-operand-of-assignment-860460/)

Ramurd 02-03-2011 07:43 AM

lvalue required as left operand of assignment
 
Hi all, it's been a long time since I did coding in C, but thought to pick up a very old project again, just to show off what I have been working on ten years ago.

I deducted my problem as follows:

Code:

#include <stdio.h>
#include <stdlib.h>

#define bit1 1
#define bit2 2
#define bit3 4
#define bit4 8
// etc .. ;-)

#define SET_BIT(var,bit) (((long long) (var) |= ((long long) (bit)))

typedef struct foo FOO;

struct foo
{
  int act;
}

int main(int argc, char *argv[])
{
  FOO *bar;

  bar=calloc(1,sizeof(FOO));
  bar->act = 0;
  printf("act: %d\n", bar->act);
  SET_BIT(bar->act,bit3);
  printf("act: %d\n",bar->act);

  return 0;
}

Now I get an error when compiling (gcc 4.3.3 under Linux, 32-bit):
Quote:

lvalue required as left operand of assignment
this is on the line
Code:

SET_BIT(bar->act,bit3);
I am 100% certain that this used to compile fine in the past (10 years ago :-o);

Why is it saying that bar->act is not a valid lvalue while both bar->act and the bit are cast to (long long)?

Ramurd 02-03-2011 08:09 AM

funnily enough:
if I change
Code:

SET_BIT(bar->act,bit3);
into

Code:

bar->act |= bit3;
it's perfectly valid, but when I change it into:

Code:

(long long}bar->act |= (long long)bit3
I get the error back... it seems the typecast is what upsets gcc.

Ideally, I'd rewrite the SET_BIT macro so that it will be accepted again, so that I don't have to go through thousands of lines of code to fix this...

Edit:
It would seem obvious to remove the cast from the SET_BIT macro; However, I'd have to analyze and see how and why. Naturally, I'm a lazy person as far as this goes, so what I'm curious about is why the cast appears to be invalid. (It's fairly possible that this SET_BIT is used elsewhere on a char, or maybe even a float or double... again: It will take a fair amount of going hence and forth in the code.) So: how could I safely typecast both the var and bit so that either is accepted as lvalue and rvalue respectively?

ForzaItalia2006 02-03-2011 09:43 AM

Hey Ramurd,

great that you got back to C programming :-)

Regarding your problem, this error message is correct and as expected. If you look into the C99 standard, you'll find the following section about cast expressions:

Quote:

6.5.4 Cast operators
[...]
4 Preceding an expression by a parenthesized type name converts the value of the
expression to the named type. This construction is called a cast. (footnote 89)

(footnote 89) A cast does not yield an lvalue. Thus, a cast to a qualified type has the same effect as a cast to the
unqualified version of the type
Though, a cast is not valid on the left side of an assignment.

Andi

Ramurd 02-03-2011 10:04 AM

Hey Forza,

Thanks; It's pretty obvious when I stopped actively coding ;-) That was around 1999, hence I did not get that standard. Thanks for pointing out that I should look at the standards. While not the answer I hoped for, (I guess I'll have to try and see if removing the casts will result in big issues), I'm glad you pointed it out.

Back to programming... (oh, and I noticed I "forgot" to free(bar) in the quick-and-dirty example... :-)

gothrog 02-03-2011 03:57 PM

I'm not sure what you are doing at a physical layer, but if you can break bits into a byte and throw them into an array you could use a ptr to an address.

I think your trying to OR the bits together to get some datatype

In this example 'payload' is the array.
Code:

            for ( int inc = 0; inc < theSize3; inc++ )
            {
              *(payload + buffCount + inc ) = outStr3[inc];
              cout << payload[buffCount + inc];
            }
            cout << endl;
            buffCount = buffCount + theSize3;


tuxdev 02-03-2011 05:49 PM

Code:

#define SET_BIT(var,bit) do { ((*(unsigned long long*) &(var) |= ((unsigned long long)1 << (bit))); } while(0)

Ramurd 02-04-2011 04:35 AM

Thanks all for giving some neat solutions and answers; should've come up with tuxdev's approach;

For now I ended up with:
Code:

#define SET_BIT(var,bit) ((*(long long*) &(var) |= ((long long)(bit))))
due to the signedness of the variables I've seen so far.

So what I can do now is this:
Code:

#include <stdlib.h>
#include <stdio.h>

#define bit1 1
#define bit2 2
#define bit3 4
#define bit4 8
#define bit5 16
#define bit6 32
#define bit7 64
#define bit8 128
#define bit9 256
#define bit10 512

#define SET_BIT(var,bit) ((*long long*) &(var) |= ((long long) (bit))))

typedef struct foo FOO;

struct foo
{
  int act;
}

int main(int argc, char *argv[])
{
FOO *bar;

bar=calloc(1,sizeof(FOO));

bar->act = 0;
printf("act: %d\n", bar->act);
SET_BIT(bar->act,bit3);
SET_BIT(bar->act,bit5);
printf("act: %d\n", bar->act);

free(bar);
return 0;
}

this will correctly return:
Quote:

act: 0
act: 20
I am aware that by shifting bits I could accomplish the same; however for simplicity's sake, I have also these macro's:
Code:

#define IS_SET(flag,bit) (flag & bit)
#define REMOVE_BIT(var,bit) ((*(long long *) &(var) &= ~((long long)(bit))))
#define TOGGLE_BIT(var,bit) ((*(long long *) &(var) ^= ((long long)(bit))))

These macro's allow for quick checking of a certain bit-flag.
The usage is in terms of
Code:

#define RECORD_DIRTY 1
#define RECORD_TYPE_TEXT 2
#define RECORD_TYPE_DATA 4
#define RECORD_TYPE_MULTIPART (RECORD_TYPE_TEXT|RECORD_TYPE_DATA) //  = 6
#define RECORD_EXPIRED 8

so, one reads only 1 (long long) integer, which is quite fast and perform certain checks based on that single integer; since it's a bitwise check/set, the method is also fairly fast and consumes little memory. There are various records with various types (all integer-based); so that these macro's are indeed widely usable.

I tagged the helpful posts as I noticed they helped me find a good solution, and quite happy that tuxdev showed how to work around the lvalue limitation regarding type casts. And marked the thread as solved. I guess this is material one does not easily figures out without some (fresh) hands-on experience. :-)


All times are GMT -5. The time now is 08:47 AM.