2010-07-30 18 views
8

Duplicar posible:
Why global and static variables are initialized to their default values?¿Por qué las variables estáticas se autoinicializan a cero?

¿Cuál es la razón técnica que esto sucede? ¿Y es compatible con el estándar en todas las plataformas? ¿Es posible que ciertas implementaciones puedan devolver variables indefinidas si las variables estáticas no se inicializan explícitamente?

+2

Votado para volver a abrir porque esta pregunta también pregunta si algunos compiladores no ponen a cero las variables estáticas. ¡La respuesta es sí! Algunos compiladores específicos de dominio no se ajustan a todos los estándares. Por ejemplo, en TIGCC (un compilador de C para calculadoras TI-89/92/V200), se conservará una variable global con una inicialización explícita (por ejemplo, 'static int high_score = 0; ') en todas las ejecuciones del programa (a menos que esté archivado) en la memoria Flash), que proporciona una forma simple pero sórdida de conservar la configuración del programa. –

Respuesta

31

Se es requerido por la norma (§6.7.8/10).

No hay ninguna razón técnica sería tiene que ser así, pero ha sido así por mucho tiempo suficiente para que el Comité de Normas hizo un requisito.

Al salir de este requisito, el trabajo con variables estáticas será algo más difícil en muchos casos (¿la mayoría?). En particular, a menudo tiene que realizar una inicialización única y necesita un estado de inicio confiable para saber si una variable en particular ya se ha inicializado o no. Por ejemplo:

int foo() { 
    static int *ptr; 

    if (NULL == ptr) 
     // initialize it 
} 

Si ptr podría contener un valor arbitrario en el arranque, que lo tienes que inicializar explícitamente a NULL para poder reconocer si que había hecho su inicialización de una sola vez todo o no.

+1

+1 para el enlace de estándares. El mandato original del comité ANSI C era codificar la práctica existente, que es más probable por qué se hizo un requisito. – paxdiablo

+3

@paxdiablo: Sin duda, está explícitamente establecido en K & R1 (Apéndice A, §6.8): "Se espera que las variables estáticas y externas que no se inicialicen comiencen como 0; las variables automáticas y de registro que no se inicializan tienen la garantía de comenzar como basura". –

0

Principalmente porque las variables estáticas están agrupadas en un bloque por el vinculador, por lo que es muy fácil simplemente memset() todo el bloque a 0 en el inicio. No quiero creer que sea requerido por los estándares C o C++.

+1

No es 'memset' a 0, excepto en DOS y otros sistemas operativos [no]. En un sistema moderno, es una referencia de copia sobre escritura a la "página cero". –

0

Hay una discusión sobre este here:

primer lugar en la norma ISO C (ANSI C), todas las variables estáticas y globales deben inicializarse antes de que comience el programa. Si el programador no hizo esto explícitamente, entonces el compilador debe establecerlos en cero. Si el compilador no hace esto, no sigue ISO C. Sin embargo, el estándar no especifica exactamente cómo se inicializan las variables.

0

Echale un vistazo: here 6.2.4 (3) y 6.7.8 (10)

9

Sí, es porque está en la norma; pero en realidad, es porque es gratis. Las variables estáticas se parecen a las variables globales del código de objeto generado. Se asignan en .bss y se inicializan en el momento de la carga junto con todas sus constantes y otras variables globales. Dado que la sección de la memoria donde viven solo se copia directamente de su ejecutable, se inicializan a un valor conocido en tiempo de compilación de forma gratuita. El valor que se eligió es 0.

+1

La sección .bss en archivos ELF es de longitud cero. Es el cargador el responsable de cero inicializando el bloque. Si el estándar no exigía esto, podría dejar el bloque sin inicializar. – doron

+5

Una página no inicializada en el inicio del proceso sería cero de todos modos, a menos que el núcleo se desvive por escribir basura al azar. En cualquier implementación moderna, bss es una referencia COW (copy-on-write) a la "página cero" que se comparte entre todos los procesos. Incluso si no fuera así, el kernel tendría que hacer algo para evitar que los nuevos procesos vean los contenidos de la memoria física aleatoria (que podría contener datos internos privados del kernel o datos de otros usuarios) así que podrían también configurarlo en un valor útil como 0 al borrarlo ... –

0

Supongamos que está escribiendo un compilador de C. Espera que algunas variables estáticas tengan valores iniciales, por lo que esos valores deben aparecer en algún lugar del archivo ejecutable que el compilador creará. Ahora cuando se ejecuta el programa de salida, todo el archivo ejecutable se carga en la memoria. Parte de la inicialización del programa es crear las variables estáticas, por lo que todos esos valores iniciales deben copiarse en sus destinos finales de variables estáticas.

¿O sí? Una vez que el programa comienza, los valores iniciales de las variables ya no son necesarios. ¿No pueden las variables mismas ubicarse dentro del código ejecutable? Entonces no hay necesidad de copiar los valores.Las variables estáticas podrían vivir dentro de un bloque que estaba en el archivo ejecutable original, y no se debe hacer ninguna inicialización para ellas.

Si ese es el caso, ¿por qué querría hacer un caso especial para las variables estáticas no inicializadas? ¿Por qué no simplemente poner un montón de ceros en el archivo ejecutable para representar las variables estáticas no inicializadas? Eso cambiaría un poco de espacio por un tiempo y una complejidad mucho menor.

No sé si algún compilador de C realmente se comporta de esta manera, pero sospecho que la opción de hacer las cosas de esta manera podría haber impulsado el diseño del lenguaje.

+0

Algunos viejos compiladores de C podrían haber puesto las variables inicializadas dentro de la imagen del código y acceder a ellas desde allí. Sé que Turbo Pascal hizo eso. No veo ninguna razón para poner allí variables no inicializadas. Llenar un bloque de memoria con cero no es difícil. – supercat

+0

@supercat - Llenar un bloque de memoria con cero no es nada difícil. Pero no es necesario segar las variables estáticas en categorías Inicializadas y Sin inicializar y asignar bloques de memoria separados para ellas, aunque tampoco es difícil. –

+0

Es "necesario" para ahorrar espacio, tanto en el disco como en la memoria. Si llama a eso "innecesario", entonces debe dejar de codificar ... –

1

Por supuesto, no se puede argumentar que está en los estándares C. Entonces, espere que un compilador compatible se comporte de esa manera.

La razón técnica detrás de por qué se hizo podría ser que esté enraizado en cómo funciona el código de inicio de C. Generalmente, hay varios segmentos de memoria en los que el enlazador debe poner la salida del compilador, incluidos un segmento de código (texto), un segmento de almacenamiento en bloque y un segmento variable inicializado.

Las variables de función no estáticas no tienen almacenamiento físico hasta que el alcance de la función se crea en tiempo de ejecución, por lo que el vinculador no hace nada con eso.

El código de programa va en el segmento de código (o texto) pero también lo hacen los valores utilizados para inicializar variables globales y estáticas. Las variables inicializadas (es decir, sus direcciones) van en el segmento de memoria inicializada. Las variables globales y estáticas no inicializadas entran en el segmento de almacenamiento en bloque (bss).

Cuando el programa se carga en el momento de la ejecución, una pequeña porción de código crea el entorno de tiempo de ejecución de C. En sistemas basados ​​en ROM, copiará el valor de las variables inicializadas del segmento de código (texto) en sus respectivas direcciones reales en la RAM. Los sistemas basados ​​en RAM (es decir, disco) pueden cargar los valores iniciales directamente en las direcciones finales de RAM.

El CRT (tiempo de ejecución de C) también pone a cero el bss que contiene todas las variables globales y estáticas que no tienen inicializadores. Esto probablemente fue hecho como una precaución contra datos no inicializados. Es una operación de relleno de bloques relativamente sencilla porque todas las variables globales y estáticas se han agrupado juntas en un segmento de dirección.

de carros de golf y dobles puede precisar un tratamiento especial debido a que su valor de 0.0 no puede ser cero todos los bits si el formato flotante no cumpla la norma IEEE 754.

Nota que desde autovariables no existen en el momento de la carga del programa ellos no pueden ser inicializados por el código de inicio del tiempo de ejecución.

+0

El estándar de punto flotante IEEE 754 está diseñado específicamente para que +0 sea cero bits. ¿Has visto una implementación de C que usa otra representación de valores de coma flotante para la cual esto no es cierto? –

+0

@Jeffrey: He utilizado compiladores para formatos de flotación específicos de DSP como TI. Pero ahora no estoy 100% seguro si también tenían esa propiedad. –

+2

@Jeffrey: No, el formato TI no codifica 0.0 como todos los bits cero. Requiere un exponente de -128 para identificar de manera única 0.0. –

Cuestiones relacionadas