Nehmen wir an, Sie haben in C eine Variable namens variable_name
. Nehmen wir an, es befindet sich in 0xaaaaaaaa
und an dieser Speicheradresse haben Sie die Ganzzahl 123. Mit anderen Worten, variable_name
enthält 123.
Ich suche nach einer Klärung der Formulierung “variable_name
liegt bei 0xaaaaaaaa
“. Wie erkennt der Compiler, dass die Zeichenfolge “Variablenname” dieser bestimmten Speicheradresse zugeordnet ist? Ist die Zeichenfolge “Variablenname” irgendwo im Speicher gespeichert? Ersetzt der Compiler nur variable_name
zum 0xaaaaaaaa
wann immer es es sieht, und wenn ja, müsste es nicht den Speicher verwenden, um diese Ersetzung vorzunehmen?
Variablennamen existieren nicht mehr, nachdem der Compiler ausgeführt wurde (mit Ausnahme von Sonderfällen wie exportierten Globals in gemeinsam genutzten Bibliotheken oder Debug-Symbolen). Der gesamte Vorgang der Kompilierung soll diese symbolischen Namen und Algorithmen, die durch Ihren Quellcode dargestellt werden, in native Maschinenanweisungen umwandeln. Also ja, wenn Sie eine globale haben variable_name
und Compiler und Linker beschließen, es auf zu setzen 0xaaaaaaaa
dann wird überall dort, wo es im Code verwendet wird, nur über diese Adresse darauf zugegriffen.
Also um deine wörtlichen Fragen zu beantworten:
Wie erkennt der Compiler, dass die Zeichenfolge “Variablenname” dieser bestimmten Speicheradresse zugeordnet ist?
Die Toolchain (Compiler & Linker) arbeiten zusammen, um einen Speicherplatz für die Variable zuzuweisen. Es ist die Aufgabe des Compilers, alle Referenzen im Auge zu behalten, und der Linker fügt später die richtigen Adressen ein.
Ist die Zeichenfolge "variable_name"
irgendwo im Gedächtnis gespeichert?
Nur während die Compiler läuft.
Ersetzt der Compiler nur variable_name
zum 0xaaaaaaaa
wann immer es es sieht, und wenn ja, müsste es nicht den Speicher verwenden, um diese Ersetzung vorzunehmen?
Ja, das ist ziemlich genau das, was passiert, außer dass es ein zweistufiger Job mit dem Linker ist. Und ja, es verbraucht Speicher, aber es ist der Compiler Speicher, nichts zur Laufzeit für Ihr Programm.
Ein Beispiel hilft vielleicht beim Verständnis. Probieren wir dieses Programm aus:
int x = 12;
int main(void)
{
return x;
}
Ziemlich einfach, oder? OK. Nehmen wir dieses Programm, kompilieren es und sehen uns die Disassemblierung an:
$ cc -Wall -Werror -Wextra -O3 example.c -o example
$ otool -tV example
example:
(__TEXT,__text) section
_main:
0000000100000f60 pushq %rbp
0000000100000f61 movq %rsp,%rbp
0000000100000f64 movl 0x00000096(%rip),%eax
0000000100000f6a popq %rbp
0000000100000f6b ret
Siehst du das movl
Linie? Es greift die globale Variable (in diesem Fall relativ zum Anweisungszeiger). Keine Erwähnung mehr von x
.
Machen wir es jetzt etwas komplizierter und fügen eine lokale Variable hinzu:
int x = 12;
int main(void)
{
volatile int y = 4;
return x + y;
}
Die Disassemblierung für dieses Programm ist:
(__TEXT,__text) section
_main:
0000000100000f60 pushq %rbp
0000000100000f61 movq %rsp,%rbp
0000000100000f64 movl $0x00000004,0xfc(%rbp)
0000000100000f6b movl 0x0000008f(%rip),%eax
0000000100000f71 addl 0xfc(%rbp),%eax
0000000100000f74 popq %rbp
0000000100000f75 ret
Jetzt sind es zwei movl
Anleitung und ein addl
Anweisung. Das sieht man erstmal movl
wird initialisiert y
, von dem entschieden wird, dass es sich auf dem Stapel befindet (Basiszeiger – 4). Dann das nächste movl
bekommt die globale x
in ein Register eax
und die addl
fügt hinzu y
zu diesem Wert. Aber wie Sie sehen können, das wörtlich x
und y
Saiten gibt es nicht mehr. Sie waren Bequemlichkeiten für Sieder Programmierer, aber der Computer kümmert sich sicher nicht um sie zur Ausführungszeit.
Der AC-Compiler erstellt zunächst eine Symboltabelle, in der die Beziehung zwischen dem Variablennamen und seinem Speicherort gespeichert ist. Beim Kompilieren verwendet es diese Tabelle, um alle Instanzen der Variablen durch einen bestimmten Speicherort zu ersetzen, wie andere angegeben haben. Auf der Wikipedia-Seite findest du noch viel mehr dazu.
Alle Variablen werden vom Compiler ersetzt. Zuerst werden sie durch Referenzen ersetzt und später platziert der Linker Adressen anstelle von Referenzen.
Mit anderen Worten. Die Variablennamen sind nicht mehr verfügbar, sobald der Compiler durchlaufen ist
Das nennt man ein Ausführungsdetails. Während das, was Sie beschreiben, bei allen Compilern, die ich je verwendet habe, der Fall ist, muss es nicht der Fall sein. Der AC-Compiler konnte jede Variable in eine Hashtabelle einfügen und sie zur Laufzeit nachschlagen (oder so ähnlich), und tatsächlich taten frühe JavaScript-Interpreter genau das (jetzt führen sie eine Just-In-TIme-Kompilierung durch, die zu etwas viel Roherem führt.)
Speziell für gängige Compiler wie VC++, GCC und LLVM: Der Compiler weist im Allgemeinen eine Variable einem Speicherort zu. Variablen mit globalem oder statischem Gültigkeitsbereich erhalten eine feste Adresse, die sich während der Ausführung des Programms nicht ändert, während Variablen innerhalb einer Funktion eine erhalten Stapel Adresse, dh eine Adresse relativ zum aktuellen Stapelzeiger, die sich jedes Mal ändert, wenn eine Funktion aufgerufen wird. (Dies ist eine zu starke Vereinfachung.) Stapeladressen werden ungültig, sobald die Funktion zurückkehrt, haben aber den Vorteil, dass sie praktisch keinen Overhead verwenden.
Sobald einer Variablen eine Adresse zugewiesen wurde, ist der Name der Variablen nicht mehr erforderlich, sodass er verworfen wird. Abhängig von der Art des Namens kann der Name zur Vorverarbeitungszeit (für Makronamen), zur Kompilierzeit (für statische und lokale Variablen/Funktionen) und zur Verbindungszeit (für globale Variablen/Funktionen) verworfen werden. Wenn ein Symbol exportiert wird ( für andere Programme sichtbar gemacht werden, damit sie darauf zugreifen können), wird der Name normalerweise irgendwo in einer “Symboltabelle” verbleiben, die tut beanspruchen eine triviale Menge an Arbeitsspeicher und Speicherplatz.
Ersetzt der Compiler einfach variable_name für 0xaaaaaaaa, wann immer er es sieht
Ja.
und wenn ja, müsste es nicht Speicher verwenden, um diese Ersetzung vorzunehmen?
Ja. Aber es ist der Compiler, nachdem er Ihren Code kompiliert hat, warum kümmern Sie sich um den Speicher?
Nicht ganz eine Antwort, aber dies könnte einige Lücken füllen: csee.umbc.edu/~chang/cs313.s02/stack.shtml
– Douglas
30. Januar 2013 um 19:47 Uhr
Nun, ohne Debug-Informationen wird der Variablenname nicht im Speicher gespeichert. Wenn Sie dies verstehen wollen, müssen Sie zuerst die Maschinensprache und die Assemblersprache verstehen.
– Heiße Licks
8. Februar 2013 um 2:02 Uhr