Que se passe-t-il lorsqu’une variable sort de la scope?

Dans la plupart des langages gérés (c‘est-à-dire ceux avec un GC), les variables locales sortant du champ d’application sont inaccessibles et ont une priorité GC supérieure (par conséquent, elles seront libérées en premier).

Maintenant, C n’est pas un langage géré, qu’advient-il des variables qui sortent du cadre ici?

J’ai créé un petit test 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); // Comstack-time error (as expected) printf("ptr = %d\n", *ptr); return 0; } 

J’utilise GCC 4.7.3 pour comstackr et le programme ci-dessus affiche 17 , pourquoi? Et quand / dans quelles circonstances les variables locales seront-elles libérées?

Le comportement réel de votre exemple de code est déterminé par deux facteurs principaux: 1) le comportement n’est pas défini par le langage, 2) un compilateur optimiseur générera un code machine qui ne correspond pas physiquement à votre code C.

Par exemple, même si le comportement n’est pas défini, GCC peut (et va) facilement optimiser votre code pour ne plus

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

ce qui signifie que la sortie que vous voyez a très peu à voir avec ce qu’il advient des variables de votre code.

Si vous souhaitez que le comportement de votre code reflète mieux ce qui se passe physiquement, vous devez déclarer vos pointeurs volatile . Le comportement sera toujours indéfini, mais au moins, il limitera certaines optimisations.

Maintenant, quant à ce qui arrive aux variables locales quand elles sortent de la scope. Rien de physique ne se passe. Une implémentation typique allouera suffisamment d’espace dans la stack de programmes pour stocker toutes les variables au niveau le plus profond d’imbrication de blocs dans la fonction actuelle. Cet espace est généralement alloué dans la stack en une seule fois au démarrage de la fonction et libéré à la sortie de celle-ci.

Cela signifie que la mémoire précédemment occupée par tmp rest réservée dans la stack jusqu’à la fermeture de la fonction. Cela signifie également que le même espace de stack peut (et sera) réutilisé par différentes variables ayant approximativement le même niveau de “profondeur de localité” dans des blocs frères. L’espace conservera la valeur de la dernière variable jusqu’à ce qu’une autre variable déclarée dans une variable de bloc frère la remplace. Dans votre exemple, personne ne remplace l’espace précédemment occupé par tmp , vous verrez donc généralement que la valeur 17 rest intacte dans cette mémoire.

Cependant, si vous faites cela

 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); } 

vous verrez que l’espace précédemment occupé par tmp a été réutilisé pour d et que sa valeur précédente a été remplacée. La seconde printf généralement la même valeur de pointeur pour les deux pointeurs.

La durée de vie d’un object automatique se termine à la fin du bloc où il est déclaré.

Accéder à un object en dehors de sa durée de vie est un comportement indéfini en C.

(C99, 6.2.4p2) “Si un object est référencé en dehors de sa durée de vie, le comportement n’est pas défini. La valeur d’un pointeur devient indéterminée lorsque l’object vers lequel il pointe atteint la fin de sa vie.”

Les variables locales sont allouées sur la stack. Ils ne sont pas “libérés” dans le sens où vous pensez aux langues du GC ou à la mémoire allouée sur le tas. Ils vont simplement hors de scope, et pour les types internes, le code ne fera rien – et pour les objects, le destructeur est appelé.

Accéder à eux au-delà de leur scope est un comportement indéfini. Vous avez juste eu de la chance, car aucun autre code n’a écrasé cette zone mémoire … pour le moment.