2010-05-28 43 views
14

¿Podría alguien explicar la diferencia en cómo se manejan los 2 fragmentos de código a continuación? Definitivamente compilan a código de ensamblado diferente, pero estoy tratando de entender cómo el código podría actuar de manera diferente. Entiendo que los literales de cadenas se arrojan a la memoria de solo lectura y son efectivamente estáticos, pero ¿cómo difiere esto de la estática explícita a continuación?Diferencia entre static const char * y const char *

struct Obj1 
{ 
    void Foo() 
    { 
     const char* str("hello"); 
    } 
}; 

y

struct Obj2 
{ 
    void Foo() 
    { 
     static const char* str("hello"); 
    } 
}; 
+2

'static const char' tiene' static' escrito antes de 'const char' – Iuliu

Respuesta

18

Con su versión estática solo habrá una variable que se almacenará en algún lugar y siempre que se ejecute la función se usará la misma variable. Incluso para llamadas recursivas.

La versión no estática se almacenará en la pila para cada llamada de función y se destruirá después de cada una.

Ahora su ejemplo es un poco complicado en cuanto a lo que el compilador de hecho lo hace vamos a ver un caso más simple primero:

void foo() { 
    static long i = 4; 
    --i; 
    printf("%l\n", i); 
} 

Y luego un principal o menos así:

int main() { 
    foo(); 
    foo(); 
    return 0; 
} 

imprimirá

3 
2 

mientras que con

void foo() { 
    long i = 4; 
    --i; 
    printf("%l\n", i); 
} 

se imprimirá

3 
3 

ahora con su ejemplo, usted tiene una constante, por lo que el valor no puede ser cambiado por lo que el compilador podría jugar algunos trucos, mientras que a menudo no tiene efecto en el código generado, pero ayuda al compilador a detectar errores. Y luego tiene un puntero, y la mente que la estática tiene efectos sobre el puntero en sí, no sobre el valor al que apunta. Así que la cadena "hola" de su ejemplo probablemente se colocará en el segmento .data de su binario, y solo una vez y vivirá mientras viva el programa, independientemente de lo estático.

+0

Sus ejemplos de código no caben aquí, la esencia de la pregunta es la "const" y el hecho de que se coloca en el segmento de datos de solo lectura, por lo que el puntero a este char parece ser estático por defecto, incluso si lo hace no poner "estático" antes de "const char *". –

+1

Quizás el compilador pueda optimizar esto y tratarlo como estático, ya que estamos tratando con un puntero aquí. Sin embargo, esto no se puede hacer en todos los casos: con void foo() {const Bar bar; } El constructor por defecto de Bar debe ser llamado para cada invocación de foo(), mientras que con void foo() {static const Bar bar; } el constructor se llama a lo sumo una vez. Además, la matriz de caracteres siempre estará en segmentos de solo lectura, la pregunta es sobre la variable str. – johannes

10

Una variable estática local es inicializa la primera vez que se encuentra su definición, pero no destruido cuando se cierra la función. Entonces mantiene su valor entre invocaciones a la función.

En el caso de const, esto no es del todo útil, al menos, siempre que construir el valor constante sea tan poco útil como la asignación de una dirección. (Si el objeto const no es una expresión constante, o la expresión toma recursos considerables para crear - como en const Foo bar = foobar();, donde foobar() puede llevar un tiempo considerable -, la diferencia podría ser importante.)

Cuando se hace la diferencia es cuando desee devolver el objeto por referencia o puntero: No puede devolver una referencia o un puntero a un objeto local, a menos que sea un objeto estático local. (Gracias a Matthieu por señalar esto.) Sin embargo, cuando quiera usar esto, debe tener en cuenta que las estáticas locales son intrínsecamente inseguras en el hilo.

+1

Creo que debe subrayar la diferencia en el tiempo de vida, puede devolver una referencia/puntero a la estática local, pero no está definido para hacerlo con un clásico variable de pila –

+0

@ Matthieu: Tienes razón, no había pensado en eso. Gracias, lo agregaré a mi respuesta. – sbi

+1

Y me alegro de que hayas agregado el bit de la cuestión de "subprocesos" :) La gente a menudo olvida que las variables estáticas locales son similares a las globales y padecen todos sus problemas. –

2

Si bien hay una diferencia técnica, en términos de uso y efecto sus dos ejemplos son idénticos.

Más detalladamente, su uso de la palabra clave static se aplica al puntero al literal de cadena, no al literal de cadena en sí. El puntero en el ejemplo 1 se colocará en la pila, el puntero en el ejemplo dos se colocará con las variables estáticas.

Me sorprendería si ambos no se optimizan a la misma cosa sin embargo.

7

He descubierto que algunos compiladores tratan los dos de manera diferente.

La versión con const char * copiará los datos de una ubicación de solo lectura a una variable en la pila.

La versión con static const char * hace referencia a los datos en la ubicación de solo lectura (no se realiza ninguna copia).

Descubrí esta diferencia al pasar por el código de ensamblaje de una función, utilizando el depurador. Le sugiero que imprima el código de ensamblado o que lo revise, en el idioma del ensamblador, con un depurador para encontrar la verdad exacta .