In Punkt 2 auf Seite 16 (Bevorzugen Sie Konstanten, Aufzählungen und Inlines gegenüber #defines) sagt Scott:
Auch wenn gute Compiler keinen Speicher für const-Objekte vom Typ Integer reservieren ...
Ich verstehe das nicht Wenn ich ein const-Objekt definiere, z
const int myval = 5;
dann muss der Compiler sicher etwas Speicher (von int-Größe) beiseite legen, um den Wert 5 zu speichern?
Oder werden const-Daten auf besondere Weise gespeichert?
Dies ist wohl eher eine Frage des Computerspeichers. Wie speichert der Computer const-Objekte, damit kein Speicher reserviert wird?
c++
computer-science
user619818
quelle
quelle
storage of const object
die Quelle Ihrer Frage wenig Wert.Antworten:
Eine etwas korrektere Aussage wäre, dass Compiler den Datenspeicher nicht für const-Objekte vom Integer-Typ reservieren würden: Sie würden ihn gegen den Programmspeicher eintauschen . Es gibt keinen Unterschied zwischen den beiden unter Von Neumann-Architektur, aber in anderen Architekturen wie Harvard ist die Unterscheidung ziemlich wichtig.
Um vollständig zu verstehen, was vor sich geht, müssen Sie sich daran erinnern, wie die Assemblersprache Daten zur Verarbeitung lädt. Es gibt zwei grundsätzliche Möglichkeiten , um die Daten zu laden , - einen Speicher von einem bestimmten Ort lesen (sogenannte direkter Adressierungsmodus) oder eine Konstante als Teil des Befehls spezifizierten Satz selbst (so genannten unmittelbarer Adressierungsmodus). Wenn der Compiler eine
const int x = 5
Deklaration gefolgt von siehtint a = x+x
, hat er zwei Möglichkeiten:x
Generieren Sie bei jeder Referenzierung eine sofortige Ladeanweisung mit dem Wert 5Im ersten Fall sehen Sie ein Einlesen
x
in das Akkumulatorregister , eine Addition des Werts am Speicherort desx
Akkumulators und einen Speicher am Speicherort des Akkumulatorsa
. Im zweiten Fall sehen Sie eine sofortige Ladung von fünf, eine sofortige von fünf, gefolgt von einem Geschäft an der Position vona
. Einige Compiler können herausfinden, dass Sie hinzufügen , eine Konstante zu sich, optimizea = x+x
ina = 10
und erzeugen eine einzige Anweisung , dass speichern zehn an der Stellea
.quelle
Nicht unbedingt. Es kann auch entschieden werden, nur den Rohwert 5 anstelle des
myval
kompilierten Codes zu verwenden.Der Unterschied zwischen
#define MYVAL 5
undconst int myval = 5
besteht darin, dass der Compiler im ersteren Fall überhaupt keine Wahl hat, da der Präprozessor bereits alle ErwähnungenMYVAL
im Quellcode5
durch ersetzt hat, bis der Compiler den Quellcode sehen kann. Im letzteren Fall gibt es jedoch eine Wahl. Bei einem nicht optimierten Debug-Build kann der Compiler explizit a zuweisenconst int
, sodass Sie im Debugger die Konstantemyval
anstelle nur des Rohwerts 5 sehen können.quelle
Ich werde den ersten Satz aus Péter Töröks Antwort stehlen, aber anders ausarbeiten: Nicht unbedingt. Es kann auch entschieden werden, nur den Rohwert 5 anstelle des
myval
kompilierten Codes zu verwenden.Die Behandlung
myval
wie eine reguläre Variable durch Zuweisen von Speicherplatz im Speicher kann Auswirkungen auf die Leistung haben, die je nach Architektur und Umgang mit dem Speicher von winzig bis schwerwiegend reichen.Auf diese Weise würde ein Compiler eine Anweisung ausgeben, die etwas in der Art von "Laderegister R mit dem, was sich an der Speicherstelle für befindet
myval
" sagt . Die Lage dermyval
als Operand des Befehls kommt er also direkt aus demselben Datenblock wie der Befehl selbst. Auf modernen CPUs ist dieser Wert aufgrund des Befehlsvorabrufs auf dem Chip leicht verfügbar. Mit der vorliegenden Adresse muss die CPU den Wert immer noch aus dem Speicher holen. Das kann schnell gehen, wenn sich der Speicherort in der Nähe im Cache befindet, oder nicht so schnell, wenn dies nicht der Fall ist. Die CPU muss nicht nur vom Chip abweichen, um den Wert zu erhalten, sondern kann auch dazu führen, dass andere, nützlichere Daten aus dem Cache entfernt werden, die später wieder eingefügt werden müssen. Wenn das Programm unter einem Betriebssystem ausgeführt wird, das den Speicher virtualisiert, kann der Zugriff auf diesen Speicherort einen Seitenfehler verursachen, der dazu führt, dass das Programm in den Ruhezustand versetzt wird, bis die erforderliche Seite über periphere (z. B. Festplatten-) E / A in den RAM gebracht wird.Durch Festverdrahtung des konstanten Werts mit dem Objektcode würde der Compiler eine Anweisung wie "Laderegister R mit dem Wert
5
" ausgeben . Wie die oben beschriebene Speicheradresse5
wäre das ein Operand für den Befehl und auf die gleiche Weise verfügbar (dh vorabgerufen). Hier endet die Ähnlichkeit, denn die CPU verfügt nun über alles, was sie benötigt, um das5
Register R zu erstellen und mit ihrem Geschäft fortzufahren. Da Adressen und Register normalerweise die gleiche Größe haben, gibt es keinen Unterschied in der Anzahl der Bytes, die der Befehl belegt, und die tatsächliche Ausführung erfolgt ohne Wahrscheinlichkeit von Cache-Fehlern und Seitenfehlern, die auftreten können, wenn Sie etwas aus dem Speicher fischen.Der Compiler könnte, wie Péter betonte, Speicherplatz und ein Symbol für
myval
Debug-Builds zuweisen . Es würde nicht schaden, dies zu tun und seinen Wert immer noch fest zu verdrahten, da der Wert auf jeden Fall derselbe bleibt und das Symbol wirklich nur für uns Menschen zum Debuggen da ist.Beachten Sie, dass dies nur für Werte gilt, die in Registern gespeichert werden können, da Register von Natur aus Ganzzahlen sind. Andere Konstanten werden im Speicher gespeichert.
quelle
Was das Zitat sagt, ist nicht ganz richtig.
Ein guter Compiler wird keinen Speicher für statische const-Variablen reservieren. Wenn die Variable const nicht statisch ist und sich im Dateibereich befindet, muss der Speicher reserviert werden, da auf die Variable von einer anderen Kompilierungseinheit verwiesen werden kann. Mit Optimierungen der Verbindungszeit kann der Linker möglicherweise die Speicher- und Umschreibanweisungen, die auf die Variable verweisen, entfernen, wenn er nachweisen kann, dass das Programm keinen Zeiger auf diese Variable generiert.
Ein viel besserer Grund für die Verwendung
const int
anstelle von#define
ist, dass Debugger keine Makros "sehen", sodass Sie einen#defined
d-Wert im Debugger nicht überprüfen können .quelle
Der Compiler ersetzt die Nummer fünf überall dort, wo die Variable 'myval' verwendet wird.
quelle
Der Compiler kann konstante Werte als unmittelbare Operanden betrachten. Sofortige Operanden erfordern keine Datenspeicherung. Der Compiler kann Folgendes behandeln:
das Gleiche wie
Der Wert 5 wird nicht im Datenspeicher gespeichert, sondern als Teil der Befehlssequenz.
Der Compiler muss die Datenspeicherung in Fällen reservieren, in denen die Adresse eines Wertes verwendet werden kann. Selbst in diesem Fall verwendet der Compiler weiterhin Sofortoperationen, wenn der Wert von myVal verwendet wird.
quelle