Normalerweise wird der r-Wert innerhalb des Programms selbst gespeichert.
Mit anderen Worten, der Compiler selbst ( bevor das Programm jemals ausgeführt wird ) berechnet den 10 + 5 - 3 Wert (dies kann er tun, da er alle auf konstanten unmittelbaren Werten basiert), und es gibt den Assembler-Code aus, um das Ergebnis dieser Berechnung in jedem beliebigen l-Wert für die Zuweisung zu speichern (in diesem Fall die Variable mit dem Namen a, die der Compiler wahrscheinlich als relative Adresse zu einem Datensegment-Ursprung von Arten kennt) / p>
Der r-Wert, der einen Wert von 12 hat, wird daher nur innerhalb der Binärdatei des Programms innerhalb einer Assemblierungsanweisung gefunden, die wie
aussieht %Vor%$ 0C ist der "r-Wert".
Wenn der r-Wert zufällig das Ergebnis einer Berechnung ist, die nur zur Laufzeit ausgeführt werden kann, sagen wir, wenn der zugrundeliegende c-Code war: a = 17 * x; // x einige Laufzeit var, der r-Wert würde auch als eine Reihe von Anweisungen innerhalb des Programmbinärs "gespeichert" (oder eher materialisiert) werden. Der Unterschied zum obigen einfachen "mov dest, imm" besteht darin, dass man mehrere Anweisungen benötigt, um die Variable x in einen Akkumulator zu laden, mit 17 zu multiplizieren und das Ergebnis an der Adresse zu speichern, an der die Variable a steht. Es ist möglich, dass der Compiler sich "authorisieren" kann ;-), um den Stack für ein Zwischenresultat etc. zu verwenden, aber das wäre ein
a) vollständig kompilerabhängig
b) transiente
c) und würde typischerweise nur Teil des r-Wertes von |
Es ist daher sicher zu sagen, dass der r-Wert ein Kompilierzeitkonzept ist, das in Teilen des Programms (nicht den Daten) eingekapselt ist und nicht irgendwo gespeichert ist, sondern in der Programm-Binärdatei.
Als Antwort auf paxdiablo: Die oben angebotene Erklärung ist in der Tat restriktiv für die Möglichkeiten, weil der c-Standard tatsächlich nichts von dieser Art diktiert. Nichtsdestoweniger wird der meiste r-Wert irgendwann, zumindest teilweise, durch einige Anweisungen realisiert, die Dinge so einrichten, dass der richtige Wert, ob berechnet (zur Laufzeit) oder unmittelbar, richtig adressiert wird.
Konstanten werden wahrscheinlich zur Kompilierzeit vereinfacht, so dass Ihre Frage, wie sie im wahrsten Sinne des Wortes gestellt wird, nicht helfen kann. Aber etwas wie, sagen wir, i - j + k
, das zur Laufzeit von einigen Variablen berechnet werden muss, kann "gespeichert" werden, wo der Compiler es mag, abhängig von der CPU-Architektur: Der Compiler wird typischerweise versuchen sein Bestes zu tun, um Register zu verwenden. zB
um einen solchen Ausdruck zu berechnen, indem er im Akkumulatorregister AX "gespeichert" wird, bevor er einem Speicherplatz mit STORE AX, dest
oder dergleichen zugewiesen wird. Ich wäre ziemlich überrascht, wenn ein moderner optimierender Compiler auf einer sogar halbwegs vernünftigen CPU-Architektur (ja, x86 enthalten! -) Register in den Speicher für irgendeinen vernünftig einfachen Ausdruck verschütten müsste!
Wo es speichert, ist es eigentlich total bis zum Compiler. Der Standard diktiert dieses Verhalten nicht.
Ein typischer Platz kann gesehen werden, indem man den Code tatsächlich kompiliert und die Assembler-Ausgabe betrachtet:
%Vor%welches produziert:
%Vor% Das relevante Bit ist mit ;*****
gekennzeichnet und Sie können sehen, dass der Wert vom Compiler erstellt und direkt in eine mov
type-Anweisung eingefügt wird.
Beachten Sie, dass dies nur so einfach ist, weil der Ausdruck ein konstanter Wert ist. Sobald Sie nicht konstante Werte (wie Variablen) einführen, wird der Code etwas komplizierter. Das liegt daran, dass Sie diese Variablen im Speicher nachschlagen müssen (oder sie können sich bereits in einem Register befinden) und dann die Werte bei Laufzeit , nicht Kompilierzeit ändern.
Wie der Compiler berechnet, was der Wert sein soll, hat mit der Auswertung von Ausdrücken zu tun und ist eine ganz andere Frage: -)
Dies ist compilerabhängig. Normalerweise wird der Wert (12) vom Compiler berechnet. Es wird dann im Code gespeichert, typischerweise als Teil einer sofortigen Assemblierungsanweisung zum Laden / Verschieben.
a
verschoben wird.
Hier ist eine Demontage von MSVC:
%Vor%Ihre Frage basiert auf einer falschen Prämisse.
Die definierende Eigenschaft von lvalue in C ist, dass es einen Platz im Speicher hat, d. h. es ist gespeichert . Dies unterscheidet Lvalue von rvalue . Rvalue ist nicht irgendwo gespeichert. Das macht es zu einem Wert. Wenn es gespeichert wäre, wäre es per Definition lvalue .
Die Ausdrücke "lvalue" und "rvalue" werden verwendet, um die Welt der Ausdrücke zu halbieren. Das heißt, (10+5-3)
ist ein Ausdruck, der zufällig ein rvalue ist (weil Sie den & amp; -Operator nicht darauf anwenden können - in C ++ sind die Regeln komplizierter). Zur Laufzeit gibt es keine Ausdrücke, L-Werte oder R-Werte. Insbesondere werden sie nirgends gespeichert.
Sie haben sich gefragt, wo der Wert 12 gespeichert wurde, aber der Wert 12 ist weder ein lvalue noch ein rvalue (im Gegensatz zum Ausdruck 12
, der ein rvalue wäre, aber 12
erscheint nicht in Ihrem Programm) .