Why according to the standard is a++ = b; disallowed, while c[i++] = d; is permitted?
(Obviously, a++ = b; would be bad style, but this is a question about a close reading of the C language standard.)
Here is the obligatory minimal example:
#include <stdio.h>
int main(void)
{
int a = 10;
int b = 20;
int i = 1;
int c[] = {30, 40};
int d = 50;
a++ = b; // error
c[i++] = d;
printf("%d\n", a); // [21]
printf("%d\n", b); // 20
printf("%d\n", i); // 2
printf("%d\n", c[0]); // 30
printf("%d\n", c[1]); // 50
printf("%d\n", d); // 50
return 0;
}
GCC emits the following error, when compiling this with -std=c90 or -std-c17:
error: lvalue required as left operand of assignment
According to K&R (2e), A7.3.4 and A7.4.1
The result [of postfix/prefix
++or--] is not an lvalue.
a++ is considered to be not an lvalue, but from what wording does it explicitly follow that c[i++] is an lvalue? Turning to the C11 standard, I can't find any provisions about either.
For what it's worth: If it weren't disallowed, I would interpret a++ = b; as a = b; a = a+1;.
Edit:
Some people have (justifiedly) asked why one would semantically assume a statement like a++ = b; to make sense.
I often try to convert tricky syntactic constructs into something equivalent-but-simpler. (Let's all admit that pre- and post-increment/decrement operators aren't just tricky; they're a syntactic catastrophe: they can be deeply embedded in a statement but have the effect of something having to be executed before or after.) I was generally going with the assumption that any non-pathological statement of the form
statement(
++w,--x,y++,z--)
is equivalent to
w += 1;
x -= 1;
statement(w,x,y,z)
y += 1;
z -= 1;
where the pre- and post-statement assignments are ordered in an implementation-defined manner. Of course the question is what counts as "non-pathological" (or whether we should even define it as "cases for which the order among the pre-increments and among the post-increments doesn't matter"), but, putting this concern aside for a moment, it is not unreasonable for a programmer to assume that pre- and post-incremented/decremented expressions are otherwise syntactically equivalent to their corresponding forms with these operators removed.
Saying that "such operators strip their argument expressions of their lvalue quality" is entirely valid and does answer my question, but:
- If this assumption isn't built into one's mindset, other interpretations (such as what I wrote above) are conceivable. (That is, from a language design perspective (and in my opinion), pre-/post-increment/decrement expressions losing their lvalue quality is not a syntactic necessity.)
- To me it seems a bit that the wording quoted from K&R ("The result [of postfix/prefix
++or--] is not an lvalue.") was put in simply to disallow assignments likea++ = b;.
c[i]is defined as*(c+i)And that give us an lvalue.
Could you modify the result of
5+1? Of course not.(5+1) = 3;makes absolutely no sense. The result of5+1is not something that can hold a value. You couldn't fetch the value you assigned to it a later time. Assigning to the result of5+1is complete nonsense.The result of
a++is the old value ofa. It can't beaitself, sinceano longer has the correct value. It just an ephemeral value like the result of5+1. It's not a something that can hold value. It makes absolutely no sense to assign to it.In technical terms,
a++isn't a modifiable lvalue because it's not an lvalue because it doesn't potentially refer to an object.References are from the C17 standard.