gcc gdb building - "lvalue required as increment operand" on *((void **)__o->next_free)++ = ((void *)datum);

StackOverflow https://stackoverflow.com/questions/21172290

  •  28-09-2022
  •  | 
  •  

Question

Trying to build the gdb package but it errors out at obstack.h with the error message

lvalue required as increment operand

Going to the location of the error gives this line of code

*((void **)__o->next_free)++ = ((void *)datum);

Can anyone explain why the error message is occurring and what should be done?

I used to think I knew the C language in and out but guess not.

From the same code source, just a few lines above the following line appears to compile without error:

*(__o->next_free)++ = 0;

They appear the same?

Was it helpful?

Solution 2

The problem is that when you perform a cast on the expression that is being incremented. The C99 standard says this in a footnote:

A cast does not yield an lvalue

And the post-increment operator requires an lvalue.

Note that due to operator precedence rules, the expression is equivalent to:

*(((void **)__o->next_free)++) = ((void *)datum);

Ie., the post-increment is acting on the void** (on which pointer arithmetic is valid), not the dereferenced void* (which is an lvalue and would be valid to post-increment - if pointer arithmetic were valid on void*).

Also note that as a language extension, GCC permits pointer arithmetic on void* (treating it similar to char*).

OTHER TIPS

If you look at the code, the next_free member is a char *, so what the code is trying to do is to store a pointer there and advancing to the next item. In particular, if you look at a bit of the code around, it's checking if __o->next_free + sizeof (void *) is beyond the chunk limit, so that makes it really clear what the code is trying to achieve.

We can just open-code it as a dereference followed by advancing to the next item:

 #define obstack_ptr_grow(OBSTACK,datum)                                \
 __extension__                                                          \
 ({ struct obstack *__o = (OBSTACK);                                    \
    if (__o->next_free + sizeof (void *) > __o->chunk_limit)            \
      _obstack_newchunk (__o, sizeof (void *));                         \
-   if (!__o->alloc_failed)                                             \
-     *((void **)__o->next_free)++ = ((void *)datum);                   \
+   if (!__o->alloc_failed) {                                           \
+     *((void **)__o->next_free) = ((void *)datum);                     \
+     __o->next_free += sizeof (void *);                                \
+   }                                                                   \
    (void) 0; })

I believe pointer math relative to a void pointer is undefined. Remember, incrementing a pointer means stepping it forward by the size of the thing it points to. What's the size of void? (Answer: void has no size, by definition.)

Addressing takes precedence over other operators, so what you're doing here is casting the value to (void **), dereferencing it to get (void *), and then trying to apply ++ to that. This may not be what you intended to do.

This code does not seem to make any sense. At the first sight it looks like it was supposed to be

(*((void **)__o->next_free))++

Any postfix operator in C has higher precedence than any prefix operator. It means that postfix ++ has higher precedence than unary *. So, in your original variant you are actually doing

*(((void **)__o->next_free)++)

I.e. you are indeed applying ++ to an rvalue - the result of the conversion to void **. It cannot possibly compile. The error message is right.

The (*((void **)__o->next_free))++ version will not have the lvalue error and will compile (assuming the compiler supports void * arithmetic as a non-standard extension). But the fact that later ((void *)datum) is assigned to the result of that expression makes it rather meaningless again (i.e. it will reintroduce the lvalue error through a different path).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top