C Optimierung von Stringliteralen

habe gerade folgendes in gdb inspiziert:

char *a[] = {"one","two","three","four"}; char *b[] = {"one","two","three","four"}; char *c[] = {"two","three","four","five"}; char *d[] = {"one","three","four","six"}; 

und ich bekomme folgendes:

 (gdb) pa $17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} (gdb) pb $18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} (gdb) pc $19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"} (gdb) pd $20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"} 

Ich bin wirklich überrascht, dass die String-pointers für entsprechende Wörter gleich sind. Ich hätte gedacht, dass jeder Zeichenfolge ein eigener Speicher auf dem Stapel zugeordnet wurde, unabhängig davon, ob es sich um eine Zeichenfolge in einem anderen Array handelte.

Ist dies ein Beispiel für eine Art von Compiler-Optimierung oder ist es Standardverhalten für eine String-Deklaration dieser Art?

Es heißt “String-Pooling”. Es ist optional in Microsoft Compilern, aber nicht in GCC. Wenn Sie das String-Pooling in MSVC ausschalten, werden die “gleichen” Strings in den verschiedenen Arrays dupliziert und haben andere Speicheradressen und würden daher zusätzliche (unnötige) 50 Bytes Ihrer statischen Daten benötigen.

EDIT: GCC hat tatsächlich eine Option, -fwritable-strings , die String-Pooling deaktiviert. Die Wirkung dieser Option ist zweifach: Sie erlaubt das Überschreiben von String-Literalen und deaktiviert das String-Pooling. In Ihrem Code würde also das Setzen dieses Flags den etwas gefährlichen Code erlauben

 /* Overwrite the first string in a, so that it reads 'xne'. Does not */ /* affect the instances of the string "one" in b or d */ *a[0] = 'x'; 

(Ich nehme an, dass a , b , c und d als lokale Variablen deklariert sind, was der Grund für Ihre stackbezogenen Erwartungen ist.)

String-Literale in C haben statische Speicherdauer. Sie werden niemals “auf dem Stapel” zugewiesen. Sie werden immer im globalen / statischen Speicher zugewiesen und leben “für immer”, dh solange das Programm läuft.

Ihre a , b , c und d Arrays wurden auf dem Stack zugewiesen. Die in diesen Arrays gespeicherten pointers zeigen auf statischen Speicher. Unter diesen Umständen ist es nichts Ungewöhnliches an pointersn, dass identische Wörter identisch sind.

Ob ein Compiler identische Literale zu einer zusammenführen wird, hängt vom Compiler ab. Einige Compiler haben sogar eine Option, die dieses Verhalten steuert. String-Literale sind immer schreibgeschützt (deshalb ist es besser, den Typ const char * für Ihre Arrays zu verwenden). Es macht also keinen großen Unterschied, ob sie zusammengeführt werden oder nicht, bis Sie sich auf den tatsächlichen pointers verlassen Werte.

PS Nur aus Neugier: Warum sollten Sie erwarten, dass identische Literale mehr als einmal “instanziiert” werden, selbst wenn diese Zeichenfolgenliterale auf dem Stack zugewiesen wurden?