Wyrażenia " j = ++(i | I); and j = ++(i & I); should be a lvalue error?
Spodziewałem się tego w moim następującym kodzie:
#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;
}
Wyrażenia j = ++(i | i);
i j = ++(i & i);
spowodują błędy lvalue jak poniżej:
x.c: In function ‘main’:
x.c:6: error: lvalue required as increment operand
x.c:9: error: lvalue required as increment operand
Ale dziwi mnie, że powyższy kod skompilowany pomyślnie, jak poniżej:
~$ gcc x.c -Wall
~$ ./a.out
11 11
12 12
Sprawdź powyższy kod działa poprawnie.
Podczas gdy inni operatorzy produkują błąd (jak rozumiem). Nawet Operator bitowy XOR powoduje błąd j = ++(i ^ i);
(sprawdź inne operatory wytwarzają błąd lvalue w czasie kompilacji).
Jaki jest powód? To jest nieokreślone czy nieokreślone ? czy operatory or I bitowe są różne?
Wersja kompilatora:
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
ale uważam, że wersja kompilatora nie powinna powodować niejednorodnego zachowania. If ^
not compiled then |
and &
also not. w przeciwnym razie powinno działać dla wszystkich
To nie jest błąd z tym kompilatorem w trybie c99: gcc x.c -Wall -std=c99
.
5 answers
Masz rację, że nie powinien kompilować, a na większości kompilatorów nie kompiluje.(proszę dokładnie określić, który kompilator / wersja nie powoduje błędu kompilatora)
Mogę tylko postawić hipotezę, że kompilator zna tożsamości (i | i) == i
i (i & i) == i
i używa tych tożsamości do optymalizacji wyrażenia, pozostawiając tylko zmienną i
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 18:26:01
Jest to błąd, który został rozwiązany w nowszych wersjach GCC.
Prawdopodobnie dlatego, że kompilator optymalizuje i & i
do i
i i | i
do i
. To wyjaśnia również, dlaczego operator xor nie działał; i ^ i
byłby zoptymalizowany do 0
, co nie jest modyfikowalnym lvalue.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 18:28:55
C11 (n1570), § 6.5.3.1 operatory przyrostowe i przyrostowe
Operand przedrostka increment lub decrement operator ma atomic, qualified, lub niewykwalifikowanym typem rzeczywistym lub wskaźnikowym i musi być modyfikowalnym lvalue .C11 (n1570), § 6.3.2.1 Lvalues, arrays, and function designators
Modyfikowalne lvalue to lvalue, które nie ma typu tablicy, nie ma typu niekompletnego, nie ma const- Typ kwalifikowany, a jeśli jest strukturą lub związkiem, nie ma żadnego członka (w tym, rekurencyjnie, każdy członek lub element wszystkich zawartych agregatów lub związków) z const- kwalifikowany Typ.C11 (n1570), § 6.3.2.1 Lvalues, arrays, and function designators
Lvalue jest wyrażeniem (z typem obiektu innym niżvoid
), które potencjalnie wyznacza obiekt.C11 (n1570), § 3. Terminy, definicje i symbole
Obiekt: Region przechowywania danych w środowisku wykonawczym, którego zawartość może reprezentować wartości
Z tego co wiem, potencjalnie oznacza "zdolny do bycia, ale jeszcze nie istnieje". Ale (i | i)
nie jest w stanie odwoływać się do regionu przechowywania danych w środowisku wykonawczym. Dlatego nie jest to lvalue. Wydaje się, że jest to błąd w starej wersji gcc, naprawiony od tego czasu. Zaktualizuj swój kompilator!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-16 14:03:16
To tylko kontynuacja mojego pytania . Dodałem rozbudowaną odpowiedź, aby można było ją znaleźć pomocną.
W moim kodzie wyrażenia
j = ++(i | i);
ij = ++(i & i);
nie są spowodowane błędem lvalue ?
Z powodu optymalizacji kompilatora, na co @abelenky odpowiedział (i | i) == i
i (i & i) == i
. Dokładnie tak.
W moim kompilatorze (gcc version 4.4.5)
każde wyrażenie zawierające pojedynczą zmienną i wynik jest niezmienione; zoptymalizowane do pojedynczej zmiennej (coś o nazwie nie wyrażenie ).
Na przykład:
j = i | i ==> j = i
j = i & i ==> j = i
j = i * 1 ==> j = i
j = i - i + i ==> j = i
==>
środki optimized to
Aby go obserwować napisałem mały kod C i zdemontowałem go za pomocą gcc -S
.
Kod C: (czytaj komentarze )
#include<stdio.h>
int main(){
int i = 10;
int j = 10;
j = i | i; //==> j = i
printf("%d %d", j, i);
j = i & i; //==> j = i
printf("%d %d", j, i);
j = i * 1; //==> j = i
printf("%d %d", j, i);
j = i - i + i; //==> j = i
printf("%d %d", j, i);
}
Wyjście montażowe: ( czytaj komentarze )
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $10, 28(%esp) // i
movl $10, 24(%esp) // j
movl 28(%esp), %eax //j = i
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl 28(%esp), %eax //j = i
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl 28(%esp), %eax //j = i
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl 28(%esp), %eax //j = i
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
W powyższym kodzie złożenia wszystkie wyrażenia zamienione na następujący kod:
movl 28(%esp), %eax
movl %eax, 24(%esp)
To odpowiednik j = i
w kodzie C. Tak więc j = ++(i | i);
i j = ++(i & i);
są zoptymalizowane do j = ++i
.
zawiadomienie: j = (i | i)
jest stwierdzeniem, gdzie jako wyrażenie (i | i)
not a statement (nop) in C
Stąd mój kod mógł się pomyślnie skompilować.
Dlaczego
j = ++(i ^ i);
lubj = ++(i * i);
,j = ++(i | k);
produkować błąd lvalue na moim kompilatorze?
Ponieważ albo wyrażenie ma wartość stałą, albo nie można modyfikować lvalue (wyrażenie nieoptymalizowane).
możemy obserwować za pomocą asm
kod
#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);
j = i * i;
printf("%d %d\n", j, i);
j = i + i;
printf("%d %d\n", j, i);
return 1;
}
Kod zestawu: ( czytaj komentarze )
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $10, 28(%esp) // i
movl $10, 24(%esp) // j
movl $0, 24(%esp) // j = i ^ i;
// optimized expression i^i = 0
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, 24(%esp) //j = i - i;
// optimized expression i - i = 0
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl 28(%esp), %eax //j = i * i;
imull 28(%esp), %eax
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl 28(%esp), %eax // j = i + i;
addl %eax, %eax
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $1, %eax
leave
Stąd więc to tworzy lvalue error
, ponieważ operand nie jest modyfikowalnym lvalue. I niejednorodne zachowanie wynika z optymalizacji kompilatora w gcc-4.4.
Dlaczego nowe Kompilatory gcc (lub większość kompilatorów) generują błąd lvalue?
Ponieważ ocena wyrażenia ++(i | i)
i ++(i & i)
zabrania rzeczywistego definacji operatora increment (++).
Operatory increment i decrement mogą być stosowane tylko do zmiennych; wyrażenie takie jak (i + j)++ jest nielegalne. Operand musi być modyfikowanym lvalue typu arytmetycznego lub wskaźnika.
Testowałem na nowym kompilatorze gcc 4.47 tutaj generuje błąd tak, jak się spodziewałem. I również testowane na kompilatorze tcc.
Wszelkie opinie/ komentarze na ten temat byłyby świetne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:28
W ogóle nie uważam, że jest to błąd optymalizacji, bo jeśli tak, to w ogóle nie powinno być żadnego błędu. Jeśli ++(i | i)
jest zoptymalizowane do ++(i)
, to nie powinno być żadnego błędu, ponieważ (i)
jest lvalue.
IMHO, myślę, że kompilator widzi {[3] } jako wyjście wyrażenia, które oczywiście wyprowadza rvalue, ale operator Przyrostowy ++
oczekuje, że lvalue ją zmieni, a więc błąd.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-16 14:34:03