Wie weiß der Compiler, dass das String-Literal (const char *) bereits im Datenspeicher existiert?

8

Ich habe das gelernt

%Vor%

verwendet "abc", um das Array szA zu initialisieren, so dass es im Stapelspeicher gespeichert wird und beim Beenden der Funktion zerstört wird.

Betrachten Sie andererseits:

%Vor%

Hier wird "abc" wie statische Variablen im Datenspeicherbereich gespeichert, und szB ist nur eine Adresse davon.

In diesem Punkt habe ich mich gefragt:

Wenn ich es versuche

%Vor%

wird dies 1000000 von "Hallo" im Datenabschnitt machen?

Um das herauszufinden, habe ich Testcode geschrieben:

%Vor%

Und das Ergebnis ist:

  

testA ---------------
  9542604
  9542608
  testB ---------------
  9542604
  9542608
  lokal ---------------
  9542604
  9542608

Offensichtlich gibt es nur einen Platz für jedes String-Literal im Datenspeicher.

Aber wie weiß der Compiler, dass die literale Zeichenfolge (const char*) bereits im Datenspeicher existiert?

    
KID 18.02.2018, 07:20
quelle

3 Antworten

4

In einigen Situationen müssen Zeichenfolgenliterale in statische Zeichenarrays konvertiert werden. Dies geschieht zur Kompilierzeit. Ihre Schleife kann den statischen Speicher nicht millionenfach zuordnen ; es ist einfach nicht möglich. Eine statische Variable kann nur einmal vergeben werden.

Der Compiler kann für jedes String-Literal, das er im Quellcode sieht, statischen Speicher zuordnen. Der Compiler kann denselben statischen Speicher für identische String-Literale verwenden, also nach char * p="Hello"; char * q="Hallo"; p und q können gleich oder ungleich sein. Der Compiler darf denselben statischen Speicher für dieselbe Bytefolge verwenden, also nach char * p="Hello"; char * q="ello"; & amp; p [1] und & amp; q [0] können gleich oder ungleich sein.

Wie gut der Compiler denselben statischen Speicher wiederverwenden kann, hängt von der Qualität des Compilers ab. Es kann nur alle String-Literale verfolgen, die Codegenerierung verzögern, bis es alle String-Literale in einer Kompilierungseinheit kennt, dann gleiche Strings mit derselben Adresse kombinieren, Suffixe wie "Hello" und "ello" kombinieren und nur die String-Literale generieren werden benötigt.

Auch für etwas wie sizeof ("Hello") oder "Hello" [2] muss kein statischer Speicher erstellt werden. Für einen Zeigervergleich, wie p == "Hallo" oder "Hallo" == "Hallo", kann der Compiler einfach sagen, dass das Ergebnis falsch ist, ohne Speicher zuzuweisen.

    
gnasher729 18.02.2018, 11:50
quelle
9

Der Compiler durchsucht die Quellcodedatei, sucht nach allen Zeichenfolgenliteralen und speichert sie. Dazu kann ein Mechanismus wie eine Nachschlagetabelle verwendet werden. Es durchläuft dann die Liste und weist allen identischen Zeichenfolgenliteralen dieselbe Adresse zu.

Was interessanter ist, ist, wie dies über verschiedene Kompilierungseinheiten im selben Projekt geschieht, da der Compiler nur eine Datei gleichzeitig verarbeitet und nichts über die anderen Dateien weiß.

In diesem Fall muss der Linker einspringen und Hilfe leisten, indem er einige Informationen zu den String-Literalen in einem Abschnitt der OBJ-Datei speichert, die für die Datei generiert wurde, wie in diesen Antworten erwähnt:

Wie fügen C ++ - Compiler identische String-Literale zusammen

Zeichenkette Literaladresse über Übersetzungseinheiten hinweg

Der letzte Punkt wirft auch den wichtigen Punkt auf, dass identische String-Literale mit der gleichen Adresse nicht von der C ++ - Spezifikation garantiert werden, sondern eher ein Implementierungsdetail.

    
Gonen I 18.02.2018 07:23
quelle
3

Ein Compiler verwendet normalerweise Hashtabellen für verschiedene Zeichenfolgen wie Bezeichner und Zeichenfolgenliterale. Es ist leicht zu wissen, ob ein Bezeichner oder ein String-Literal mindestens einmal aufgetreten ist. Wann immer der Compiler ein String-Literal sieht, prüft er, ob dieselbe Zeichenfolge schon einmal aufgetreten ist, und wenn ja, wird er die gleiche Zeichenfolge für den nächsten Zeiger verwenden, den er sieht.

    
iBug 18.02.2018 07:31
quelle

Tags und Links