Wenn ich eine Variable deklariere, zB:
%Vor% Was genau ist x
? eine Adresse im Speicher ist normalerweise hexadezimal
Auch wenn ich X rufe.
Woher weiß der Compiler, wo x
ist? x
ist keine Adresse.
Das war meine erste Frage.
Zweitens:
Nehmen wir an, ich habe ein Objekt:
Person p;
p
hat 2 Datenmember:
Was genau ist p
, und warum muss ich zu p
gehen, dann die Variable?
Im Fall int x = 6
ist x
nur ein Name, der Ihnen hilft, den Code zu schreiben, und der Compiler kompiliert ihn. Es ist im Grunde ein Alias für einen Platz im Speicher, so dass es später leichter ist, über x = 2
darauf zuzugreifen - das sagt Ihnen und dem Compiler, dass Sie den Wert 2
an derselben Stelle schreiben wollen.
Wie zuvor, aber es braucht mehr Platz ( sizeof(Person)
um genau zu sein). p->type1
ist nur gültig, wenn p
ein Zeiger auf ein Person
ist (oder wenn Sie den ->
-Operator überladen haben, aber das ist nicht der Fall), p.type1
ist die für ein Objekt verwendete Syntax, um das zu spezifizieren Teil des es Sie zugreifen möchten.
Hier ist x
ein Bezeichner, d. h. name given to memory area
, wo der Wert 6 gespeichert ist.
x
ist ein einfacher Name, um nur den Speicherbereich zu identifizieren, in dem der Wert 6 gespeichert ist.
Wenn Sie eine Variable deklarieren, speichert dieser Zeit-Compiler Ihren Variablennamen in der Bezeichner-Tabelle.
Für person p
wird hier noch einmal p
dem Speicherbereich zugewiesen, der zwei Datenelemente type1
& amp; type2
Für den Zugriff auf den Wert von type1
& amp; type2
, zuerst müssen Sie den Speicherbereich finden, wo sie gespeichert sind. Deshalb müssen Sie zuerst auf den Speicherbereich p
& amp; Dann können Sie auf type1 * type2
x
ist ein Lvalue, was "Lokatorwert" bedeutet. Es heißt so, weil der Compiler von x
weiß, wo er sich befindet. Also ist x
gewissermaßen eine Adresse oder etwas, das es ermöglicht, eine Adresse abzuleiten.
Das Ding wird nur beim Lesen zu einem Wert
%Vor% In diesem Fall nimmt der Compiler x
, liest den Wert an seinem Ort und fortan steht in dieser Initialisierung x
für seinen Wert. Leider ist dieses "Wertlesen" ein impliziter Prozess. Ob also der Text x
ein Wert oder ein Lvalue ist, hängt davon ab, wo er erscheint.
Was genau ist X?
x
ist eine Variable, die als Name definiert werden kann, der einem Speicherort im Speicher zugewiesen wird.
Woher weiß der Compiler, wo x ist?
Es gibt eine so genannte Symboltabelle , die der Compiler intern verwendet, um Variablennamen den tatsächlichen Speicherpositionen zuzuordnen.
x
ist ein Variablenbezeichner. Eine Variable unterscheidet sich von einer Adresse dadurch, dass sie eine Größe hat und nicht null sein kann. Die Adresse von x
kann mit &x
erhalten werden. Betrachten Sie diesen Code:
Nun, obwohl du nur den Wert von x
geändert hast, erhältst du auch 6, wenn du den Wert von *p
(genannt Dereferenzieren des Zeigers) bekommst. p
ist auch eine Variable, aber es hat den Typ 'Zeiger auf int' anstatt 'int', was der Typ x
hat.
Dass es eine Variable ist, ist alles, was man mit Vertrauen sagen kann.
Es hat möglicherweise keine Speicheradresse, wenn das Optimierungsprogramm es in ein Register gestellt hat. Wenn es eine Speicheradresse hat, könnte es eine feste absolute Adresse (für Globals und Statik in nicht verschiebbarem Code), eine Adresse relativ zu einem anderen Objekt (für nicht statische Member) oder eine Adresse relativ zum Stack erhalten Rahmen (für automatische lokale Variablen).
Es ist möglicherweise nicht einmal ein Speicherort, wenn der Compiler feststellt, dass er den Wert immer vorhersagen und diesen Wert bei jeder Verwendung ersetzen kann.
Wenn Sie den Operator &
address-of für die Variable verwenden, muss der Compiler ihm einen Speicherort geben.
x
ist eine Variable. Oder genauer der Name oder die Bezeichnung des Ortes, an dem die Information (Daten) gespeichert ist, auf die sich diese Variable bezieht.
Sie benötigen Labels, um zwischen verschiedenen Variablen zu unterscheiden. Es ist nur für Sie (der Programmierer) da, um Ihnen zu helfen.
p
ist wieder eine Variable, aber vom Typ Person
. Und Person
ist eine Datenstruktur - sie enthält Daten, auf die Sie über die Struktur zugreifen.
Und p
ist ein Objekt (z. B. Instanziierung der Struktur) dieses Typs. Sie können zwei Objekte des gleichen Typs haben
Um zu wissen, auf welche Daten / Mitglieder Sie zugreifen möchten, verwenden Sie p.data
someone.data
Warum p->data
?
p->data
Syntax entspricht (*p).data
Das erklärt, was Zeiger ist. Wie ich schon sagte Variable ist ein Ort, wo Sie einige Informationen (Daten) speichern. Einfach gesagt, der Zeiger ist eine Variable, die eine Speicheradresse speichert. Mit anderen Worten, es zeigt auf einen anderen Wert, der irgendwo im Speicher gespeichert ist
Zum Beispiel:
%Vor% *p
in (*p).data
heißt Dereferenzieren eines Zeigers (Zugreifen auf den Wert, auf den der Zeiger zeigt)
Für weitere Informationen ist es eine gute Idee, Google-Zeiger oder noch besser eine Buch zum Lesen
Das Wort ist nicht die Sache.
Alle x
und p
, und für diese Angelegenheit p.type1
sind Namen oder Bezeichner. Also, ich denke, du fragst wirklich nach was sie identifizieren . Die Antwort ist, dass sie etwas identifizieren, das sich wie verhält, als ob es bestimmte Anforderungen der Sprachspezifikation erfüllt. Was diese identifizierte Sache tatsächlich ist, hängt von Ihrer Plattform, Ihrem Compiler, vielleicht von welchen Optimierungen, usw. ab usw.
Nehmen wir also die Aussage
%Vor% Sie sagen, dass x
jetzt (in diesem Bereich und möglicherweise verschachtelten Bereichen) auf ein int
(was auch immer das ist) verweist und ihm den anfänglichen ganzzahligen Literalwert 6
gibt.
Also, was ist ein int
? Es ist eine Sache , die einen einzelnen (positiven oder negativen) ganzzahligen Wert im Bereich [std::numeric_limits<int>::min(),std::numeric_limits<int>::max()]
enthalten kann. Seine genaue Größe ist architekturabhängig, aber mindestens so groß wie ein char
und nicht größer als ein long
(IIRC).
Wahrscheinliche Kandidaten für das, was diese Sache sein könnte:
int
auf Ihrer Plattform ist, verbunden mit einem Linkersymbol (möglicherweise zur Laufzeit verschoben), wenn es sich um eine globale Deklaration handelt, so dass der gesamte Code auf x
denselben Speicherort verwendet li>
int
zu speichern: Wenn du nie die Adresse von x
nimmst, kann es sein ganzes Leben in einem Register verbringen, aber wenn du entweder die Adresse nimmst oder der Compiler läuft Aus den Registern für alle Ihre Variablen (oder müssen sie über einen Funktionsaufruf hinweg gespeichert werden), kann x
in ein Register geladen werden, wenn Sie damit arbeiten, und zurück zum Stack verschüttet werden. Auch hier ist es an dem Compiler, sich an zu erinnern, wenn x
momentan ein Register ist (und welches) und wenn es ein Speicherort ist Wie Sie sehen, kann das "Ding" x
wirklich viele Dinge an verschiedenen Stellen während der Ausführung Ihres Programms ausmachen.
Es sei denn, Sie optimieren etwas oder legen Ihren Speicher sorgfältig aus. Eine nützlichere Frage ist was sind die Eigenschaften von x ?
Der Sinn des Standards (oder einer anderen Sprachspezifikation) besteht darin, einige nützliche Garantien über Typen, Variablen und Verhaltensweisen zu geben und dann den Compiler entscheiden zu lassen, wie diese Garantien erreicht werden.
Nehmen wir einen Schritt zurück ... es ist wichtig zu verstehen, dass alle Programmiersprachen (abgesehen von der Assemblersprache) eine Abstraktion eines Problems in Begriffen beschreiben, die für Programmierer leicht zu denken sind. Es ist die Aufgabe des Compilers, diese abstrakte Beschreibung zu lesen und eine Beschreibung auf niedrigerer Ebene zu generieren, die direkt der Hardware entspricht.
Wenn Sie schreiben:
%Vor%Sie sagen dem Compiler, dass Sie eine Integer-Variable verwenden möchten, dass Sie die Variable x aufrufen wollen und dass die Variable den Wert 6 haben soll.
Einer der Jobs des Compilers ist zu entscheiden, wie diese Variable gespeichert wird. Die C ++ - Sprache beschreibt verschiedene Arten von Variablenbereichen, die dem Compiler helfen zu entscheiden, welche Art von Speicher geeignet ist.
Eine lokale Variable (innerhalb einer Funktion deklariert) wird normalerweise im Speicher des Stacks gespeichert, aber ein kleiner Wert (wie eine ganze Zahl) könnte in einem Register gespeichert werden.
Eine globale oder statische Variable wird im Speicher gespeichert.
Der Compiler merkt sich, wo er den Wert gespeichert hat, so dass er ihn wiederfinden kann - für ein lokales Varable, das der Registername oder eine Adresse relativ zum oberen Teil des Stacks sein wird; Für eine globale oder statische Adresse wird es eine Adresse sein, die sich auf den Anfang aller Programmdaten bezieht.
Die tatsächliche Adresse im Speicher ist nicht bekannt, bis das Programm kompiliert, verknüpft und in den Speicher geladen wurde (weil das OS das Programm nicht immer an der gleichen Adresse lädt) - wichtig ist, dass der Compiler es weiß wo die Variable sein wird und dass sie Code generieren kann, um darauf zuzugreifen.
Wenn, wie in Ihrer zweiten Frage, der Typ der Variablen eine Datenstruktur ist, wählt der Compiler genau auf die gleiche Weise, wo er in den Speicher eingefügt werden soll. Wenn Ihr Programm auf einen Member dieser Struktur zugreift, kann der Compiler die Adresse des Members ermitteln, da er die Adresse der Struktur und auch den Offset des Members innerhalb der Struktur kennt.
Also, im Falle Ihres person p
Beispiels, wenn das Programm auf p1.type2
verweist, nimmt der Compiler die Adresse von p
und fügt den Offset von type2
hinzu (was wahrscheinlich 4 ist, weil der erste Ein Teil Ihrer struct person
wird mit type1
aufgegriffen, was eine Ganzzahl ist, die 4 Bytes beträgt (bei den meisten 32-Bit-Architekturen)).
Sie müssen sowohl p
als auch type2
angeben, da Sie möglicherweise eine andere Person haben (zB q
) und dem Compiler mitgeteilt werden muss, welche Person Sie manipulieren wollen. p.type2
ist nicht dieselbe Variable wie q.type2
und hat eine andere Adresse.
Lesen Sie über Stack und Heaps.
x wird mit einer eindeutigen Adresse auf den Stapel geschoben. Aber Sie müssen nur x anrufen.
aber versuchen Sie cout & lt; & lt; & amp; x;
Das ist die wirkliche Adresse
Wenn Sie Ihre Variable deklarieren, ordnet Ihr Compiler sie mit einer Variablenattributtabelle zu. Und diese Tabelle enthält Adresse und Größe, Typ usw. Der Compiler holt bei Bedarf Dinge aus dieser Tabelle.
Tags und Links c++