Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't the result of this cast an lvalue?

I need some advice with this strange behavior – lets have this code:

int ** p;

This compiles without any trouble:

p++;

But this:

((int**)p)++;

Gives me this error message: “error: lvalue required as increment operand”.

I am casting to p to the type it already is, nothing changes, so what is the problem? This is simplified version of problem I came across, when I was trying to compile one old version of gdb. So I suppose, that this worked and something changed. Any idea what is wrong with the second example?

like image 374
Pavel Avatar asked Jan 27 '14 16:01

Pavel


People also ask

What does Lvalue mean?

lvalue:- lvalue simply means an object that has an identifiable location in memory (i.e. having an address). In any assignment statement “lvalue” must have the capability to store the data.

Should I cast the result of malloc?

In C, you don't need to cast the return value of malloc . The pointer to void returned by malloc is automagically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed.

Do you need to cast malloc in C?

Declaration for malloc: void *malloc(size_t *size*); In C it is not mandatory to cast a void pointer to any other pointers, but in C++ is must.

Why we use typecasting in malloc?

Casting the result of malloc() to the appropriate pointer type enables the compiler to catch subsequent inadvertent pointer conversions. When allocating individual objects, the "appropriate pointer type" is a pointer to the type argument in the sizeof expression passed to malloc() .


2 Answers

Old versions of gcc support something called "lvalue casts" -- if you cast something that is an lvalue the result is an lvalue and can be treated as such. The main use for it is allowing you to increment a pointer by an amount corresponding to a different size:

int *p;
++(char *)p;  /* increment p by one byte, resulting in an unaligned pointer */

This extension was deprecated some time around gcc v3.0 and removed in gcc v4.0

To do the equivalent thing in more recent versions of gcc, you need do an addition and assignment (instead of an increment) casting the pointer to the type for the addition and back for the assignment:

p = (int *)((char *)p + 1);

Note that trying to dereference the pointer after this is undefined behavior, so don't count on it doing anything useful.

like image 121
Chris Dodd Avatar answered Nov 10 '22 06:11

Chris Dodd


When you typecast an expression, the result of that expression is an rvalue rather than an lvalue. Intuitively, a typecast says "give me the value that this expression would have if it had some other type," so typecasting a variable to its own type still produces an rvalue and not an lvalue. Consequently, it's not legal to apply the ++ operator to the result of a typecast, since ++ requires an lvalue and you're providing an rvalue.

That said, it is in principle possible to redefine the C language so that casting a value to its own type produces an lvalue if the original expression is an lvalue, but for simplicity's and consistency's sake I suppose the language designers didn't do this.

Hope this helps!

like image 41
templatetypedef Avatar answered Nov 10 '22 06:11

templatetypedef