Warum sagen Bücher "der Compiler reserviert Speicherplatz für Variablen im Speicher"? Ist es nicht die ausführbare Datei, die das macht? Ich meine zum Beispiel, wenn ich das folgende Programm schreibe,
#include <iostream>
using namespace std;
int main()
{
int foo;
return 0;
}
und kompiliere es und erhalte eine ausführbare Datei (lass es program.exe sein). Wenn ich jetzt program.exe starte, wird diese ausführbare Datei selbst befehlen, etwas Platz für die Variable foo zu reservieren. Wird es nicht Bitte erklären Sie, warum Bücher immer wieder sagen: "Der Compiler wird dies tun ... das tun".
sizeof
Frage befindet sich nun unter Warum wird sizeof als Operator zur Kompilierungszeit bezeichnet?Antworten:
Sie haben Recht, dass der Compiler als solcher nicht mehr vorhanden ist, wenn Ihr Programm tatsächlich ausgeführt wird. Und wenn es auf einer anderen Maschine läuft, ist der Compiler nicht mehr verfügbar.
Ich vermute, dies ist eine klare Unterscheidung zwischen dem tatsächlich von Ihrem eigenen Code zugewiesenen Speicher. Der Compiler fügt Code in Ihr Programm ein, der die Speicherzuweisung vornimmt (wie bei der Verwendung von new-, malloc- oder ähnlichen Befehlen).
Bücher verwenden daher "der Compiler tut dies oder das" oft, um zu sagen, dass der Compiler Code hinzugefügt hat, der in Ihren Codedateien nicht explizit erwähnt wird. Es stimmt, dass dies nicht genau das ist, was los ist. Unter diesem Gesichtspunkt wären viele Dinge, die in Tutorials erwähnt werden, falsch, müssten aber ausführlich erklärt werden.
quelle
malloc
et. al.Das hängt von der Variablen ab. Das Betriebssystem ordnet Heap zu, das Programm ordnet Stack zu und der Compiler ordnet Speicherplatz für Globals / Statics zu, dh sie sind in die Exe selbst integriert. Wenn Sie 1 MB globalen Speicher zuweisen, erhöht sich Ihre Exe-Größe um mindestens 1 MB
quelle
int test[256][1024]; int main(){ test[0][0]=2; return 0; }
dieses kleine Programm 1 MB zugewiesen, generiert aber nur eine 1,4-KB-Objektdatei und eine 8,4-KB-ausführbare Datei. Es sollte jedoch die richtige Größe des Arbeitsspeichers verwenden.int a1=1,a2=2,
... bis ..., a1048576=1048576;
Nur dann würdest du definitiv etwas größer als 1 MB bekommen, denke ich.was der Compiler wird tun , ist Ihren Code nehmen und es in Maschinencode kompiliert. Was Sie erwähnen, ist ein gutes Beispiel, bei dem ein Compiler nur übersetzen muss.
Zum Beispiel, wenn Sie schreiben
Sie können dies als "Ich sage dem Compiler zu" in der Ausgabe, die er generiert ] genügend RAM für ein int zu reservieren, auf das ich später verweisen kann. Der Compiler wird wahrscheinlich eine Ressourcen-ID oder einen Mechanismus verwenden, um foo in der zu verfolgen." Maschinencode, Sie können foo in einer Textdatei verwenden, anstatt Assembly zu schreiben! Hurra !
Sie können dies auch betrachten, wenn der Compiler einen Brief ( oder vielleicht einen Roman / eine Enzyklopädie ) an alle Zielprozessoren und -geräte schreibt . Der Buchstabe ist in Binärsignalen geschrieben, die (im Allgemeinen) durch Ändern des Ziels in verschiedene Prozessoren übersetzt werden können. Jeder "Brief" und / oder jede Kombination kann alle Arten von Anfragen und / oder Daten senden - wie zum Beispiel, weisen Sie dieser Variablen, die der Programmierer verwendet hat, Platz zu.
quelle
Das Sprichwort "Der Compiler weist Speicher zu" mag im wörtlichen Sinne nicht sachlich korrekt sein, aber es ist eine Metapher, die auf die richtige Weise andeutet.
Was wirklich passiert, ist, dass der Compiler ein Programm erstellt, das seinen eigenen Speicher zuweist. Es ist jedoch nicht das Programm, das den Speicher zuweist, sondern das Betriebssystem.
Was wirklich passiert, ist, dass der Compiler ein Programm erstellt, das seinen Speicherbedarf beschreibt. Das Betriebssystem verwendet diese Beschreibung, um Speicher zuzuweisen. Abgesehen davon, dass das Betriebssystem ein Programm ist und Programme eigentlich nichts tun, beschreiben sie eine Berechnung, die von der CPU durchgeführt wird. Abgesehen davon, dass die CPU nur eine komplizierte elektronische Schaltung ist, kein anthropomorphisierter kleiner Homonculus.
Aber es ist sinnvoll, sich Programme, Compiler und CPUs als kleine Menschen vorzustellen, die in einem Computer leben, nicht weil sie es tatsächlich sind, sondern weil dies eine Metapher ist, die gut zum menschlichen Gehirn passt.
Einige Metaphern eignen sich gut für die Beschreibung von Dingen auf einer Abstraktionsebene, funktionieren auf einer anderen Ebene jedoch nicht so gut. Wenn Sie auf der Ebene des Compilers denken, ist es sinnvoll, den Vorgang des Generierens von Code zu beschreiben, der zur Zuweisung von Speicher führt, wenn das zu kompilierende Programm tatsächlich als "Speicherzuweisung" ausgeführt wird. Es ist nah genug, dass wir, wenn wir darüber nachdenken, wie ein Compiler funktioniert, die richtige Idee haben und es nicht so langwierig ist, dass wir vergessen, was wir getan haben. Wenn wir versuchen, diese Metapher auf der Ebene des kompilierten Programms zu verwenden, das ausgeführt wird, ist dies auf seltsame Weise irreführend, was Ihnen aufgefallen ist.
quelle
Es ist der Compiler, der entscheidet, wo eine Variable gespeichert werden soll - entweder im Stack oder in einem freien Register. Unabhängig von der vom Compiler getroffenen Speicherentscheidung wird der entsprechende Maschinencode für den Zugriff auf diese Variable generiert und kann zur Laufzeit nicht geändert werden. In diesem Sinne ist der Compiler für die Zuweisung von Speicherplatz für Variablen verantwortlich, und die endgültige program.exe verhält sich zur Laufzeit nur blind wie ein Zombie.
Verwechseln Sie dies nicht mit einer anderen dynamischen Speicherverwaltung wie malloc, new oder möglicherweise Ihrer eigenen Speicherverwaltung. Compiler beschäftigen sich mit variablem Speicher und Zugriff, aber es ist egal, was ein tatsächlicher Wert in einem anderen Framework / einer anderen Bibliothek bedeutet. Beispielsweise:
Während der Laufzeit kann malloc eine beliebige Zahl zurückgeben, dem Compiler ist es jedoch egal, wo diese Zahl gespeichert werden soll.
quelle
Eine genauere Formulierung wäre: - "Der Compiler weist den Loader an, Platz für die Variablen zu reservieren".
In einer C-ish-Umgebung gibt es drei Arten von Platz für Variablen:
Auf einem modernen Betriebssystem wird der Heap-Speicher nicht reserviert, sondern nach Bedarf zugewiesen.
quelle
Ja, Sie haben Recht, in diesem Fall (Deklaration einer Variablen in einer Funktion) ist der Satz Ihres Buches wahrscheinlich falsch: Wenn Sie eine Variable in einer Funktion deklarieren, wird sie beim Aufrufen der Funktion auf dem Stapel zugeordnet. Auf jeden Fall sollte ein Compiler die Situation optimieren: Wenn die Funktion nicht rekursiv ist (
main()
ein guter Kandidat dafür ist), ist es in Ordnung, sie zur Kompilierungszeit zuzuweisen (auf dem BSS).(Wenn Sie neugierig sind, wo sich Ihre Variablen befinden, können Sie dies auf schmutzige Weise überprüfen (wenn Sie die Struktur der obj-Datei sowieso nicht untersuchen möchten, warum nicht?), Damit Sie eine andere Art von Variablen deklarieren können: Konstante, statisch, dynamisch,
malloc()
-zugeordnet usw. und zeigen ihre Adressen an (verwenden Sie zur besseren Lesbarkeit den%X
Formatierer inprintf()
. Die auf dem Stapel befindlichen Variablen haben sehr unterschiedliche Speicheradressen.)quelle
Das Einzige, was zur Laufzeit gemacht wird, ist, den Stack-Poinbter um einen bestimmten Betrag anzustoßen. Der Compiler entscheidet also vorher:
Diese kann als "Zuordnung" bezeichnet werden, nimmt aber während der Kompilierungszeit natürlich nur in dem Modell Platz, das der Compiler des laufenden Programms hat.
quelle