Optimización en C de los literales de cuerdas.
string gcc (2)
(Supongo que sus a
, b
, d
están declaradas como variables locales, que es la razón de sus expectativas relacionadas con la pila).
Los literales de cadena en C tienen duración de almacenamiento estático. Nunca se asignan "en la pila". Siempre se asignan en memoria global / estática y en vivo "para siempre", es decir, siempre que el programa se ejecute.
Sus arrays a, b
, d
fueron asignados en la pila. Los punteros almacenados en estas matrices apuntan a la memoria estática. En estas circunstancias, no hay nada inusual en los indicadores para que las palabras idénticas sean idénticas.
Si un compilador fusionará literales idénticos en uno, dependerá del compilador. Algunos compiladores incluso tienen una opción que controla este comportamiento. Los literales de cadena son siempre de solo lectura (por lo que es una mejor idea usar const char *
type para sus arreglos), por lo que no hace mucha diferencia si se combinan o no, hasta que comienza a confiar en el puntero real valores.
PD Solo por curiosidad: incluso si estos literales de cadena se asignaran en la pila, ¿por qué esperarías que se "instanciaran" literales idénticos más de una vez?
Solo he estado inspeccionando lo siguiente en 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"};
y me sale lo siguiente:
(gdb) p a
$17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p b
$18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p c
$19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"}
(gdb) p d
$20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"}
Estoy realmente sorprendido de que los punteros de cadena sean iguales para palabras equivalentes. Pensé que a cada cadena se le habría asignado su propia memoria en la pila, independientemente de si era lo mismo que una cadena en otra matriz.
¿Es este un ejemplo de algún tipo de optimización del compilador o es un comportamiento estándar para la declaración de cadenas de este tipo?
Se llama "agrupación de cadenas". Es opcional en los compiladores de Microsoft, pero no en GCC. Si desactiva la agrupación de cadenas en MSVC, las cadenas "iguales" en las diferentes matrices se duplicarán y tendrán diferentes direcciones de memoria, por lo que ocuparán unos 50 bytes adicionales (innecesarios) de sus datos estáticos.
EDITAR: gcc antes de v 4.0 tenía una opción, -fwritable-strings
que deshabilitó la agrupación de cadenas. El efecto de esta opción era doble: permitía que los literales de cadena se sobrescribieran y deshabilitara la agrupación de cadenas. Entonces, en su código, establecer esta bandera permitiría el código algo peligroso
/* 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'';