2012-09-12 12 views
8

Cuando compilar y ejecutar siguiente programa C en mi máquina Linux x86_64, compilado por GCC:¿Dónde se almacenan las constantes de cadena almacenadas por GCC y desde dónde se asignan estos punteros?

#include <stdio.h> 

int main(void) 
{ 
    char *p1 = "hello";    // Pointers to strings 
    char *p2 = "hello";    // Pointers to strings 
    if (p1 == p2) {     // They are equal 
    printf("equal %p %p\n", p1, p2); // equal 0x40064c 0x40064c 
             // This is always the output on my machine 
    } 
    else { 
    printf("NotEqual %p %p\n", p1, p2); 
    } 
} 

siempre me dan el resultado como:

igual 0x40064c 0x40064c

I comprende que las cadenas se almacenan en una tabla constante, pero la dirección es demasiado baja en comparación con la memoria asignada dinámicamente.

Comparar con siguiente programa:

#include <stdio.h> 

int main(void) 
{ 
    char p1[] = "hello";    // char arrar 
    char p2[] = "hello";    // char array 
    if (p1 == p2) { 
    printf("equal %p %p\n", p1, p2); 
    } 
    else {        // Never equal 
    printf("NotEqual %p %p\n", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710 
             // Different pointers every time 
             // Pointer values too large 
    } 
} 

Los dos punteros no son iguales, ya que estos son dos matrices que pueden ser manipulados de forma independiente.

Quiero saber cómo GCC genera el código para estos dos programas y cómo se asignan a la memoria durante la ejecución. Como esto ya estaría documentado, muchas veces los enlaces a la documentación también son bienvenidos.

+0

Siempre podría centrarse en el desmontaje. Es una buena habilidad para desarrollar, tendrás que volver a hacerlo en el futuro. –

+0

Solo hay dos cadenas en su código de ejemplo: 'igual% p% p \ n' y' NotEqual% p% p \ n'. 'p1' y' p2' son solo variables de matriz de caracteres inicializadas a algún valor, que luego se utiliza como una cadena. En particular, aún puede hacer 'p1 [0] = 'H'; p2 [0] = 'J'; 'por ejemplo, sin ningún problema. Si desea que 'p1' y' p2' sean constantes de cadena, use 'static const char p1 [] =" Hello ";'. Al menos GCC-4.6.3 trata las matrices de const locales como variables, no como constantes de solo lectura verdaderas, por lo que se necesita 'static '. Y no fusiona cadenas, por lo que los dos tienen punteros distintos. ¿Qué compilador estás usando? –

Respuesta

11

En ambos casos, el compilador emite los bytes de la cadena "hello" sólo una vez, en la sección .rodata del programa (Rodata siglas de de sólo lectura de datos).

En realidad, se asignan directamente desde el archivo ejecutable a la memoria, algo similar a la sección del código. Es por eso que están muy lejos de los asignados dinámicamente.

continuación:

char *p = "hello"; 

simplemente inicializa p a la dirección de este (sólo lectura) de datos. Y, obviamente, :

char *q = "hello"; 

Obtiene la misma dirección. Esto se llama string pooling y es una optimización popular opcional del compilador.

Pero cuando escribe:

char p[] = "hello"; 

Probablemente generará algo como esto:

char p[6]; 
memcpy(p, "hello", 6); 

Siendo el "hello" realidad la dirección de la cadena de sólo lectura agrupada.

La llamada a memcpy es solo para fines ilustrativos. Puede muy bien copiar en línea, en lugar de hacerlo con una llamada a función.

Si más tarde que hace:

char q[] = "hello"; 

Se definirá otra matriz y otro memcpy(). Entonces los mismos datos, pero diferentes direcciones.

¿Pero dónde residirán estas variables de matriz? Bueno eso depende.

  • Si son variables locales, no estáticas, en la pila.
  • Si son variables globales: entonces estarán en la sección .data del ejecutable, y se guardarán allí con los caracteres correctos, por lo que no es necesario memcpy en tiempo de ejecución. Lo cual es bueno, porque ese memcpy tendría que ejecutarse antes del main.
  • Si son variables estáticas locales: exactamente lo mismo que con las variables globales. Los dos juntos se llaman variables of static duration o algo así.

Acerca de los enlaces de documentación, lo siento, no conozco ninguno.

¿Pero quién necesita documentación si puede hacer los experimentos usted mismo? Para eso, la mejor herramienta disponible es objdump, ¡puede desensamblar el programa, volcar las secciones de datos y mucho más!

Espero que esto responda a sus preguntas ...

+0

Hay mucho más simple que 'objdump', simplemente use' -S' en lugar de '-c' para producir el ensamblador. –

+0

@JensGustedt: concedido. Solo estoy acostumbrado a la salida de 'objdump'. – rodrigo

+0

Puede que tampoco necesite 'memcpy' y que guarde el' "hello" 'directamente como palabras de pila. – oldrinb

Cuestiones relacionadas