¿Qué sucede cuando una variable queda fuera del scope?

En la mayoría de los lenguajes administrados (es decir, los que tienen un GC), las variables locales que salen del scope son inaccesibles y tienen una prioridad GC más alta (por lo tanto, se liberarán primero).

Ahora, C no es un lenguaje administrado, ¿qué sucede con las variables que están fuera del scope aquí?

Creé un pequeño caso de prueba en C:

#include  int main(void){ int *ptr; { // New scope int tmp = 17; ptr = &tmp; // Just to see if the memory is cleared } //printf("tmp = %d", tmp); // Compile-time error (as expected) printf("ptr = %d\n", *ptr); return 0; } 

Estoy usando GCC 4.7.3 para comstackr y el progtwig de arriba imprime 17 , ¿por qué? ¿Y cuándo / en qué circunstancias se liberarán las variables locales?

El comportamiento real de su muestra de código está determinado por dos factores principales: 1) el comportamiento no está definido por el idioma, 2) un comstackdor de optimización generará código de máquina que no coincide físicamente con su código C.

Por ejemplo, a pesar de que el comportamiento no está definido, GCC puede (y lo hará) optimizar fácilmente su código a un mero

 printf("ptr = %d\n", 17); 

lo que significa que la salida que ve tiene muy poco que ver con lo que le sucede a cualquier variable en su código.

Si desea que el comportamiento de su código refleje mejor lo que ocurre físicamente, debe declarar que sus punteros son volatile . El comportamiento aún no estará definido, pero al menos restringirá algunas optimizaciones.

Ahora, en cuanto a qué sucede con las variables locales cuando salen del scope. Nada físico sucede. Una implementación típica asignará suficiente espacio en la stack de progtwigs para almacenar todas las variables en el nivel más profundo de anidación de bloques en la función actual. Este espacio normalmente se asigna en la stack de una vez al inicio de la función y se devuelve a la salida de la función.

Esto significa que la memoria ocupada anteriormente por tmp continúa siendo reservada en la stack hasta que la función finalice. Eso también significa que el mismo espacio de stack puede (y será) reutilizado por diferentes variables que tengan aproximadamente el mismo nivel de “profundidad de localidad” en bloques hermanos. El espacio mantendrá el valor de la última variable hasta que alguna otra variable declarada en alguna variable del bloque hermano lo anule. En su ejemplo, nadie anula el espacio ocupado anteriormente por tmp , por lo que normalmente verá que el valor 17 sobrevive intacto en esa memoria.

Sin embargo, si haces esto

 int main(void) { volatile int *ptr; volatile int *ptrd; { // Block int tmp = 17; ptr = &tmp; // Just to see if the memory is cleared } { // Sibling block int d = 5; ptrd = &d; } printf("ptr = %d %d\n", *ptr, *ptrd); printf("%p %p\n", ptr, ptrd); } 

Verá que el espacio anteriormente ocupado por tmp se ha reutilizado para d y se ha anulado su valor anterior. El segundo printf típicamente generará el mismo valor de puntero para ambos punteros.

La vida útil de un objeto automático finaliza al final del bloque donde se declara.

El acceso a un objeto fuera de su tiempo de vida es un comportamiento indefinido en C.

(C99, 6.2.4p2) “Si se hace referencia a un objeto fuera de su tiempo de vida, el comportamiento no está definido. El valor de un puntero se vuelve indeterminado cuando el objeto al que apunta llega al final de su vida útil”.

Las variables locales se asignan en la stack. No se “liberan” en el sentido en que piensas en los lenguajes de GC, o en la memoria asignada en el montón. Simplemente salen del scope, y para los tipos integrados el código no hará nada, y para los objetos, se llama al destructor.

Acceder a ellos más allá de su scope es un comportamiento indefinido. Tuviste suerte, ya que ningún otro código ha sobreescrito ese área de memoria … todavía.