C optimisation des littéraux de chaîne

vient d’inspecter les éléments suivants dans gdb:

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

et j’obtiens ce qui suit:

 (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"} 

Je suis vraiment surpris que les pointeurs de chaîne soient les mêmes pour des mots équivalents. J’aurais pensé que chaque chaîne aurait eu sa propre mémoire sur la stack, qu’elle soit identique ou non à une chaîne d’un autre tableau.

S’agit-il d’un exemple d’optimisation du compilateur ou s’agit-il d’un comportement standard pour une déclaration de chaîne de ce type?

Cela s’appelle “groupement de chaînes”. C’est facultatif dans Microsoft Comstackrs, mais pas dans GCC. Si vous désactivez le regroupement de chaînes dans MSVC, les “mêmes” chaînes dans les différents tableaux seront dupliquées et auront des adresses mémoire différentes, ce qui nécessiterait environ 50 octets supplémentaires (inutiles) de vos données statiques.

EDIT: gcc a en fait une option -fwritable-ssortingngs qui désactive le pooling de chaînes. L’effet de cette option est double: il permet d’écraser les littéraux de chaîne et désactive le pooling de chaînes. Donc, dans votre code, définir ce drapeau permettrait au code quelque peu dangereux

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

(Je suppose que vos a , b , c et d sont déclarés en tant que variables locales, ce qui explique vos attentes vis-à-vis de la stack.)

Les littéraux de chaîne en C ont une durée de stockage statique. Ils ne sont jamais alloués “sur la stack”. Ils sont toujours alloués dans la mémoire globale / statique et vivent “pour toujours”, c’est-à-dire tant que le programme est exécuté.

Vos tableaux a, b , c et d ont été alloués sur la stack. Les pointeurs stockés dans ces tableaux pointent vers la mémoire statique. Dans ces circonstances, il n’y a rien d’inhabituel dans le fait que des pointeurs soient identiques pour des mots identiques.

Que le compilateur fusionne des littéraux identiques en un seul dépend du compilateur. Certains compilateurs ont même une option qui contrôle ce comportement. Les littéraux de chaîne sont toujours en lecture seule (c’est pourquoi il est préférable d’utiliser le type const char * pour vos tableaux). Ainsi, peu importe qu’ils soient fusionnés ou non, jusqu’à ce que vous commenciez à vous fier au pointeur réel. valeurs.

PS Juste par curiosité: même si ces littéraux de chaîne étaient alloués sur la stack, pourquoi vous attendriez-vous à ce que des littéraux identiques soient “instanciés” plus d’une fois?