I was expecting that in my following code:
#include<stdio.h>
int main(){
int i = 10;
int j = 10;
j = ++(i | i);
printf("%d %d\n", j, i);
j = ++(i & i);
printf("%d %d\n", j, i);
return 1;
}
expressions j = ++(i | i);
and j = ++(i & i);
will produce lvalue errors as below:
x.c: In function ‘main’:
x.c:6: error: lvalue required as increment operand
x.c:9: error: lvalue required as increment operand
But I surprised that above code compiled successfully, as below:
~$ gcc x.c -Wall
~$ ./a.out
11 11
12 12
Check the above code working correctly.
While other operators produce error (as I understand). Even bitwise operator XOR causes of an error j = ++(i ^ i);
(check other operators produce an lvalue error at compilation time).
What is the reason? Is this is unspecified or undefined ? or bitwise OR AND operators are different?
compiler version:
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
But I believe compiler version shouldn't reason for non-uniform behavior. If ^
not compiled then |
and &
also not. otherwise should work for all
Its not an error with this compiler in c99 mode: gcc x.c -Wall -std=c99
.
Just a follow-up to my question . I added elaborate answer so that one can find it helpful.
Because of compiler optimization as @abelenky answered
(i | i) == i
and(i & i) == i
. That is exactly CORRECT.In my compiler
(gcc version 4.4.5)
, any expression that includes single variable and result is unchanged; optimized into a single variable (something called not an expression).for example:
==>
meansoptimized to
To observe it I written a small C code and disassemble that with
gcc -S
.C-Code: (read comments)
assembly output: (read comments)
In above assembly code all expressions converted into following code:
that is equivalent to
j = i
in C code. Thusj = ++(i | i);
and andj = ++(i & i);
are optimized toj = ++i
.Notice:
j = (i | i)
is a statement where as expression(i | i)
not a statement (nop) in CHence my code could successfully compiled.
Because either expression has the constant value or not modifiable lvalue (unoptimized expression).
we can observe using
asm
codeassembly code: (read comments)
Hence so this produce an
lvalue error
because operand is not a modifiable lvalue. And non-uniform behavior is due to compiler optimization in gcc-4.4.Because evaluation of expression
++(i | i)
and++(i & i)
prohibits actual defination of increment(++) operator.According to Dennis M. Ritchie's book "The C Programming Language" in section "2.8 Increment and Decrement Operators" page 44.
I tested on new gcc compiler 4.47 here it produces error as I was expecting. I also tested on tcc compiler.
Any feedback/ comments on this would be great.
This is a bug that has been addressed in more recent GCC versions.
It's probably because the compiler optimizes
i & i
toi
andi | i
toi
. This also explains why the xor operator didn't work;i ^ i
would be optimized to0
, which is not a modifiable lvalue.As far as I know, potentially means "capable of being but not yet in existence". But
(i | i)
is not capable of referencing a region a data storage in the execution environment. Therefore it is not an lvalue. This seems to be a bug in an old gcc version, fixed since. Update your compiler!I don't think at all it is an optimization error, because if it was, then there should not be any error in the first place. If
++(i | i)
is optimized to++(i)
, then there should not be any error, because(i)
is an lvalue.IMHO, I think that the compiler sees
(i | i)
as an expression output, that, obviously, outputs rvalue, but the increment operator++
expects an lvalue to change it, thus the error.You are right that it should not compile, and on most compilers, it does not compile.
(Please specify exactly which compiler/version is NOT giving you a compiler error)I can only hypothesize that the compiler knows the identities that
(i | i) == i
and(i & i) == i
and is using those identities to optimize away the expression, just leaving behind the variablei
.This is just a guess, but it makes a lot of sense to me.