Question
en C, j'ai ce morceau de code:
int a;
a = 10 + 5 - 3
J'ai envie de demander:où est (10+5-3) stockés chez?(Autant que je sache, a
est situé sur la pile, et (10+5-3)
?Comment est-ce rvalue calculée?)
La solution
Typiquement, la valeur r est "stocké" dans le programme lui-même.
En d'autres termes, le compilateur lui-même ( avant que le programme est exécuté jamais ) calcule 10 + 5 - valeur 3 (il peut le faire depuis puisqu'il est basé sur des valeurs immédiates constantes), et il émet le code assembleur pour stocker le résultat de ce calcul quel que soit l valeur pour l'assignement (dans ce cas, la variable nommé, que le compilateur sait probablement comme une adresse par rapport à une origine de segment de données de toutes sortes).
La valeur r, qui a une valeur de 12 est donc seulement trouvé à l'intérieur du binaire du programme, dans une instruction de montage que regarde comme
mov <some dest, typically DS-relative>, $0C
$ 0C est la "valeur r".
Si la valeur r est arrivé à être le résultat d'un calcul qui ne peut faire au moment de l'exécution, par exemple si le code c était sous-jacente: a = 17 * x; // x temps var run, la valeur r serait trop « stockée » (ou plutôt matérialisée) comme une série d'instructions dans le fichier binaire du programme. La différence avec le simple « mov dest, imm » ci-dessus est qu'il faudrait plusieurs instructions pour charger la variable x dans un accumulateur, il faut multiplier par 17 et stocker le résultat à l'adresse où une variable est. Il est possible que le compilateur peut « autoriser lui-même » ;-) à utiliser la pile pour une etc. résultat intermédiaire, mais ce serait
a) complètement dépendant compilateur
b) transiant
c) et généralement cela reviendrait uniquement partie de la valeur r
il est donc sûr de dire que la valeur r est un concept de compilation qui est encapsulé dans certaines parties du programme (et non les données), et ne sont pas stockées, mais nulle part dans le binaire du programme.
En réponse à paxdiablo: l'explication ci-dessus est en effet restrictif des possibilités parce que la norme c fait effectivement pas dicter quoi que ce soit de cette nature. Jamais le moins, la plupart une valeur r est finalement matérialisée, au moins en partie, par des instructions qui fixe les choses de telle sorte que la valeur appropriée, que ce soit calculée (au moment de l'exécution) ou s'adresse correctement immédiate.
Autres conseils
Constantes sont probablement simplifiées au moment de la compilation, de sorte que votre question littéralement posée ne peut pas aider. Mais quelque chose comme, disons, i - j + k
qui n'a pas besoin d'être calculé lors de l'exécution de certaines variables, peuvent être « stockés » où le compilateur aime, en fonction de l'architecture du processeur: le compilateur essaiera généralement de faire de son mieux pour utiliser les registres, par exemple
LOAD AX, i
SUB AX, j
ADD AX, k
pour calculer une telle expression « stocker » dans le registre accumulateur AX, avant de l'affecter à un certain emplacement de mémoire avec STORE AX, dest
ou analogue. Je serais très surpris si un compilateur moderne sur une optimisation de l'architecture CPU même semi-décent (oui, x86 inclus -)! Nécessaire pour renverser les registres à la mémoire pour une expression assez simple
Cela dépend compilateur. En général, la valeur (12) sera calculé par le compilateur. Il est ensuite stocké dans le code, typiquement en tant que partie d'une charge / déplacement instruction de montage immédiat.
Où il stocke il est en fait totalement jusqu'à compilateur. La norme ne dicte pas ce comportement.
typique lieu peut être vu en compilant en fait le code et regardant la sortie de l'assembleur:
int main (int argc, char *argv[]) {
int a;
a = 10 + 5 - 3;
return 0;
}
qui produit:
.file "qq.c"
.def ___main;
.scl 2;
.type 32;
.endef
.text
.globl _main
.def _main;
.scl 2;
.type 32;
.endef
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $12, -4(%ebp) ;*****
movl $0, %eax
leave
ret
Le bit est marqué ;*****
pertinent et vous pouvez voir que la valeur est créée par le compilateur et vient d'être inséré directement dans une instruction de type mov
.
Notez que ce n'est que ce simple parce que l'expression est une valeur constante. Dès que vous introduisez les valeurs non constantes (comme les variables), le code devient un peu plus compliqué. C'est parce que vous devez regarder ces variables dans la mémoire (ou ils peuvent déjà être dans un registre), puis manipuler les valeurs à run-time , pas compilation .
En ce qui concerne la façon dont le compilateur calcule ce que la valeur devrait être, c'est de faire l'évaluation de l'expression et est une toute autre question: -)
- Le résultat du calcul dans le RHS (-côté de droite) est calculée par le compilateur dans une étape que l'on appelle « propagation constant ».
- Ensuite, il est stocké comme un opérande de l'instruction d'assemblage déplaçant la valeur dans
a
Voici un démontage de MSVC:
int a;
a = 10 + 5 - 3;
0041338E mov dword ptr [a],0Ch
Votre question est fondée sur une prémisse erronée.
La propriété de définir lvalue en C est ce qu 'il a une place dans le stockage, i.e. il est stockée . C'est ce qui différencie lvalue de rvalue . Rvalue est pas stockés partout. C'est ce qui en fait un rvalue. Si elle était stockée, il serait lvalue par définition.
Les termes "lvalue" et "rvalue" sont utilisés à traversent le monde des expressions.Qui est, (10+5-3)
est une expression qui se trouve être une rvalue (parce que vous ne pouvez pas appliquer l'opérateur & pour elle -- en C++, les règles sont plus complexes).Au moment de l'exécution, il n'y a pas des expressions, des lvalues ou rvalues.En particulier, ils ne sont pas stockées n'importe où.
Vous vous demandez où la valeur 12 est stockée, mais la valeur 12 est ni une lvalue, ni une rvalue (par opposition à l'expression 12
ce qui serait une rvalue, mais 12
n'apparaît pas dans votre programme).