Was ist der Grund für die folgende C-Char Array-Speicherimplementierung?

8

Was ist der Grund für die Implementierung der folgenden char-Array-Implementierung?

%Vor%

Entsprechend dem Buch Head first C (Seite 73,74) wird das Array ch2[] sowohl im konstanten Code-Segment als auch im Funktionsstapel gespeichert. Was ist der Grund für das Duplizieren von Code und Speicherplatz stapeln? Warum kann der Wert nur im Stapel gespeichert werden, wenn es sich nicht um schreibgeschützte Daten handelt?

    
Ashwin 20.08.2015, 06:41
quelle

3 Antworten

3
  

Wir erhalten Seg Fehler , da der Wert in der Konstante gespeichert wird   Codesegment

Dies ist falsch: Ihr Programm stürzt ab, weil es ein Signal empfängt, das auf eine Segmentverletzung hinweist ( SIGSEGV ), wodurch das Programm standardmäßig beendet wird. Aber das ist nicht der Hauptgrund. Das Ändern eines String-Literals ist undefiniertes Verhalten , unabhängig davon, ob es in schreibgeschützten Segmenten gespeichert ist oder nicht, was viel breiter ist, als Sie denken.

  

Array wird sowohl im konstanten Code-Segment als auch in der Funktion gespeichert   Stapel.

Dies ist ein Implementierungsdetail und sollte Sie nicht betreffen: Was ISO C betrifft, machen diese Aussagen keinen Sinn. Dies bedeutet auch, dass es anders umgesetzt werden könnte.

Wenn Sie

%Vor%

"World" , welches ein String-Literal ist, wird in ch2 kopiert, etwas, was Sie tun würden, wenn Sie malloc und Zeiger verwenden würden. Nun, warum wird das kopiert?

Ein Grund dafür könnte sein, dass es etwas ist, was Sie erwarten würden. Wenn Sie ein solches Zeichenfolgenliteral ändern könnten, was ist, wenn ein anderer Teil des Codes darauf Bezug nimmt und diesen Wert erwartet? Freigegebene Zeichenfolgenliterale sind effizient, da Sie sie in Ihrem Programm gemeinsam nutzen und Speicherplatz sparen können.

Indem Sie es kopieren, haben Sie Ihre eigene Kopie der Zeichenfolge (Sie "besitzen") und Sie können sie wie gewünscht ändern.

Zitieren "Begründung für American National Standard für Information Systems Programmiersprache C"

  

String-Literale sind als unmodierbar gekennzeichnet. Diese Spezifikation ermöglicht es Implementierungen, Kopien von Zeichenfolgen mit identischem Text zu teilen, Zeichenfolgenliterale im schreibgeschützten Speicher zu platzieren und bestimmte Optimierungen durchzuführen. String-Literale haben jedoch nicht das Typarray von const char, um die Probleme der Zeigerartprüfung zu vermeiden, insbesondere bei Bibliotheksfunktionen, da das Zuweisen eines Zeigers zu const char zu einem einfachen Zeiger auf char nicht gültig ist.

    
edmz 20.08.2015, 06:56
quelle
7

Lasst uns zuerst etwas klären. String-Literale sind nicht notwendigerweise schreibgeschützte Daten, es ist lediglich ein undefiniertes Verhalten, das versucht wird, sie zu ändern.

Es muss nicht unbedingt muss abstürzen, es kann gut funktionieren. Da es sich jedoch um ein nicht definiertes Verhalten handelt, sollten Sie sich nicht darauf verlassen, wenn Sie möchten, dass der Code in einer anderen Implementierung, einer anderen Version derselben Implementierung oder sogar am nächsten Mittwoch ausgeführt wird.

Dies könnte durchaus aus einer Zeit stammen, bevor es Standards gab (das ursprüngliche ANSI / ISO-Mandat bestand darin, bestehende Praktiken zu kodifizieren, anstatt eine neue Sprache zu schaffen). In vielen Implementierungen teilen Zeichenfolgen Platz für Effizienz, wie den Code:

%Vor%

ergibt:

%Vor%

Wenn Sie also eines der Zeichen in good geändert haben, ändert sich auch bad .

Der Grund, warum Sie es mit etwas wie tun können:

%Vor%

ist, dass, während good und bad auf ein Zeichenfolgenliteral zeigen, diese Anweisung tatsächlich ein Zeichenarray erstellt, das groß genug ist, um "meh" zu enthalten, und dann die Daten kopiert > 1 . Die Kopie der Daten kann frei geändert werden.

In der Tat zitiert das C99-Begründungsdokument dies ausdrücklich als einen der Gründe:

  

String-Literale müssen nicht veränderbar sein. Diese Spezifikation ermöglicht Implementierungen, Kopien von Zeichenfolgen mit identischem Text zu teilen, Zeichenfolgenliterale im Nur-Lese-Speicher zu platzieren und bestimmte Optimierungen durchzuführen.

Aber egal wie warum, der Standard ist ziemlich klar auf der was. Von C11 6.4.5 String literals :

  

7 / Es ist nicht spezifiziert, ob diese Arrays unterschiedlich sind, vorausgesetzt, ihre Elemente haben die entsprechenden Werte. Wenn das Programm versucht, ein solches Array zu ändern, ist das Verhalten nicht definiert.

Im letzteren Fall ist dies in 6.7.6 Declarators und 6.7.9 Initialisation enthalten.

1 Obwohl hier die normalen "Als-ob" -Regeln zu beachten sind (solange eine Implementierung so funktioniert, als ob sie dem Standard folgt, kann sie tun, was sie will).

>

Mit anderen Worten, wenn die Implementierung erkennen kann, dass Sie niemals versuchen, die Daten zu ändern, kann sie die Kopie problemlos umgehen und das Original verwenden.

    
paxdiablo 20.08.2015 06:55
quelle
2

Dies ist nur eine Teilantwort mit einem Gegenbeispiel zu einer Behauptung, dass ein String-Literal in einem Nur-Lese-Speicher gespeichert ist:

%Vor%

gcc -O6 -S c.c

%Vor%

Hier wird nur die Semantik des Konzepts literal implementiert; das wörtliche "world \ 0" existiert nicht einmal.

In der Praxis wählt ein optimierender Compiler nur dann, wenn die String-Literale lang genug sind, memcpy data aus dem Literal-Pool zu stapeln, wobei das Vorhandensein des Literals als Nullterminierungszeichenfolge erforderlich ist.

Die Semantik von char *ch1 = "Hello"; OTOH erfordert, dass irgendwo ein lineares Array existiert, dessen Adresse dem Zeiger ch1 zugeordnet werden kann.

    
Aki Suihkonen 20.08.2015 07:45
quelle

Tags und Links