Reputation: 75
I'm confused why my compiler is throwing an error in the following condition:
void funcExample (void * p_Buf, uint16_t len)
{
uint16_t i;
for (i = 0; i < len; i++) {
otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue
}
}
but if I cast prior to pass to otherFunc, it's fine because no problem incrementing a non-void pointer:
void funcExample (void * p_Buf, uint16_t len)
{
uint16_t i;
uint8_t * p_Buf_8bit;
p_Buf_8bit = (uint8_t *) p_Buf;
for (i = 0; i < len; i++) {
otherFunc (p_Buf_8bit++);
}
}
can't the void pointer be incremented once cast? am i missing something fundamental here?
Upvotes: 6
Views: 9689
Reputation: 25752
Cast operators in c:
6.5.4. p5 Preceding an expression by a parenthesized type name converts the value of the expression to the named type. This construction is called a cast. 104) A cast that specifies no conversion has no effect on the type or value of an expression.
104) 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
But the unary operator ++
requires an lvalue as stated:
6.5.3.1. p1 The operand of the prefix increment or decrement operator shall have atomic, qualified, or unqualified real or pointer type, and shall be a modifiable lvalue.
Therefore you can do:
p_Buf = ( uint8_t* )p_Buf + 1 ;
Where p_Buf
is lvalue and ( uint8_t* )p_Buf
is rvalue.
Let me just note that in your second example you don't cast( as you said ), but you declare a uint8_t pointer. Then when you use ++
on it you don't perform any casts( because it has the correct type ) and the operation is valid.
Upvotes: 5
Reputation: 5677
The answer @2501 posted is absolutely correct, but doesn't explain why the standard requires an lvalue for post-increment. The basic reason is that you need an lvalue (variable or memory location) for post-increment to perform its increment.
When you cast p_Buf
to an uint8_t*
type, you've created an rvalue in C. In simple terms, rvalues represent transient values that can be passed to functions, assigned to variables, etc. Post-increment returns the original value and then updates the variable or memory location where the value was stored, incrementing it. Because they only exist for the duration of the expression, rvalues cannot be updated, and post-increment cannot operate on them. Thus the problem with
otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue
is that the ((uint8_t *)pBuf)
is just an rvalue expression with no actual storage location. In effect, the cast means that you're only using the value of p_Buf
, and no longer directly using the variable p_Buf
.
On the other hand, when you assign the cast to a variable:
p_Buf_8bit = (uint8_t *) p_Buf;
then the variable p_Buf_8bit
is an lvalue, which represent a variable or memory location. This can be post-incremented, making this a perfectly well-formed statement in C:
otherFunc (p_Buf_8bit++);
Upvotes: 1
Reputation: 786
Incrementing a void
pointer in C
is bad idea. Most compilers don't even let it to be compiled. Use this instead:
p_Buf = (uint8_t*)p_Buf + 1;
Upvotes: 1
Reputation: 224864
The result of a cast operation is an rvalue, not an lvalue. ((uint8_t *)p_Buf)++
is simply not legal C code.
Upvotes: 0