Juste un suivi de ma question . J'ai ajouté une réponse élaborée pour que quelqu'un puisse la trouver utile.
Dans mes expressions de code j = ++(i | i);
et j = ++(i & i);
ne sont pas causés par une erreur de valeur lvalue ?
A cause de l'optimisation du compilateur comme l'a répondu @abelenky (i | i) == i
y (i & i) == i
. C'est exactement CORRECT.
Dans mon compilateur (gcc version 4.4.5)
toute expression comprenant une seule variable et dont le résultat est inchangé ; optimisée en une seule variable (ce que l'on nomme pas une expression ).
par exemple :
j = i | i ==> j = i
j = i & i ==> j = i
j = i * 1 ==> j = i
j = i - i + i ==> j = i
<code>==></code> signifie <code>optimized to</code>
Pour l'observer, j'ai écrit un petit code C et je l'ai désassemblé avec gcc -S
.
C-Code : ( lire les commentaires )
#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);
}
sortie de l'assemblage : ( lire les commentaires )
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
Dans le code d'assemblage ci-dessus, toutes les expressions sont converties en code suivant :
movl 28(%esp), %eax
movl %eax, 24(%esp)
qui est équivalent à j = i
en code C. Ainsi, j = ++(i | i);
et et j = ++(i & i);
sont optimisés pour j = ++i
.
Avis : j = (i | i)
est une déclaration alors que l'expression (i | i)
pas une déclaration (nop) en C
Ainsi, mon code a pu être compilé avec succès.
*Pourquoi j = ++(i ^ i);
o `j = ++(i i);,
j = ++(i | k);` produit une erreur lvalue sur mon compilateur ?**
Parce que l'une ou l'autre expression a la valeur constante ou lvalue non modifiable (expression non optimisée).
nous pouvons observer en utilisant <code>asm</code> 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);
j = i * i;
printf("%d %d\n", j, i);
j = i + i;
printf("%d %d\n", j, i);
return 1;
}
code d'assemblage : ( lire les commentaires )
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
Ainsi, cela produit un lvalue error
parce que l'opérande n'est pas une valeur l modifiable. Et Le comportement non-uniforme est dû à l'optimisation du compilateur dans gcc-4.4.
Pourquoi les nouveaux compilateurs gcc (ou la plupart des compilateurs) produisent une erreur lvalue ?
Parce que l'évaluation de l'expression ++(i | i)
y ++(i & i)
interdit la définition réelle de l'opérateur d'incrémentation (++).
Selon le livre de Dennis M. Ritchie " Le langage de programmation C " dans la section "2.8 Opérateurs d'incrémentation et de décrémentation" page 44.
Les opérateurs d'incrémentation et de décrémentation ne peuvent être appliqués qu'à des variables ; une expression comme (i+j)++ est illégale. L'opérande doit être une lvalue modifiable de type arithmétique ou pointeur.
J'ai testé sur de nouvelles compilateur gcc 4.47 ici il produit l'erreur à laquelle je m'attendais. J'ai également testé sur le compilateur tcc.
Toute réaction ou commentaire à ce sujet serait le bienvenu.