2012-07-09 16 views
19

solo estado inspeccionando el siguiente en GDB:optimización de cadenas literales C

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 el 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 muy sorprendido de que los punteros de cadena son los mismos para equivalente palabras. Pensé que a cada cuerda se le habría asignado su propia memoria en la pila, independientemente de si era igual a una cadena en otra matriz.

Es este un ejemplo de algún tipo de optimización del compilador o se trata de un comportamiento estándar para la declaración de cadena de este tipo?

+1

¿De dónde vino la "pila" incluso en esta pregunta? Si declaras 'a',' b', 'c' y' d' como variables locales, tienes que decirlo en tu pregunta. – AnT

+0

sí - son variables locales de duración automática declaradas dentro de una función, por lo tanto, en la pila – bph

+2

Sí. Es un ejemplo de optimización del compilador. – Jack

Respuesta

24

Se llama "agrupación de cadenas". Es opcional en Microsoft Compilers, pero no en GCC. Si desactivas el agrupamiento de cadenas en MSVC, las "mismas" cadenas en las diferentes matrices se duplicarían y tendrían diferentes direcciones de memoria, por lo que ocuparía unos 50 bytes adicionales (innecesarios) de tus datos estáticos.

EDITAR: gcc tiene de hecho tiene una opción, -fwritable-strings que deshabilita la agrupación de cadenas. El efecto de esta opción es doble: permite sobrescribir los literales de cadena y deshabilita 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'; 
+4

En GCC (4.7 como mínimo), un interruptor para deshabilitar la agrupación es -fno-merge-constants. – dbrank0

+3

@ dbrank0 tenga en cuenta que [gcc ya no admite fwritabe-srings] (https://gcc.gnu.org/gcc-4.0/changes.html), sería ideal agregar estas dos notas a su respuesta. –

7

(I asumir que su a, b, c y d se declaran como variables locales, lo cual es la razón de sus expectativas relacionadas con la pila.)

literales de cadena en C tienen una duración de almacenamiento estático. Nunca se asignan "en la pila". Siempre se asignan en la memoria global/estática y viven "para siempre", es decir, mientras se ejecuta el programa.

Sus matrices a, b, c y d se asignaron en la pila. Los punteros almacenados en estas matrices apuntan a la memoria estática. En estas circunstancias, no hay nada inusual en los punteros para que las palabras idénticas sean idénticas.

Ya sea un compilador se fusionará literales idénticos en un solo depende del compilador. Algunos compiladores incluso tienen una opción que controla este comportamiento. Los literales de cadena son siempre de solo lectura (razón por la cual es una mejor idea usar el tipo const char * para sus matrices), por lo que no importa mucho si se combinan o no, hasta que comiencen a confiar en los valores reales del puntero.

P.S. Solo por curiosidad: incluso si estos literales de cadenas estuvieran asignados a la pila, ¿por qué esperarías que los literales idénticos se "instanciaran" más de una vez?

+1

genial - eso me ayudó a entender mucho, no había entendido completamente el material literal de cadena y su duración de almacenamiento asociada - Estaba pensando erróneamente en las cadenas como variables locales (automáticas) en la pila – bph

+2

Nada de lo que tenga conocimiento dice que dos (o más) referencias al mismo literal de cadena * deben * resolverse en la misma ubicación de memoria. El compilador podría (y algunos lo hacen) asignar almacenamiento para cada literal de cadena, incluso si algunos son "duplicados". Consulte "agrupación de cadenas" mencionado por @Josh. –