Si je crée une variable dans un nouvel ensemble d'accolades, cette variable est-elle sortie de la pile sur l'accolade fermante ou est-elle suspendue jusqu'à la fin de la fonction? Par exemple:
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
Prendront de la d
mémoire pendant la code that takes a while
section?
Réponses:
Non, les accolades n'agissent pas comme un cadre de pile. En C, les accolades désignent uniquement une portée de dénomination, mais rien n'est détruit et rien n'est sorti de la pile lorsque le contrôle en sort.
En tant que programmeur écrivant du code, vous pouvez souvent y penser comme s'il s'agissait d'un cadre de pile. Les identificateurs déclarés dans les accolades ne sont accessibles que dans les accolades, donc du point de vue du programmeur, c'est comme s'ils étaient poussés sur la pile lorsqu'ils sont déclarés, puis apparus lorsque la portée est sortie. Cependant, les compilateurs n'ont pas à générer du code qui pousse / affiche quoi que ce soit à l'entrée / à la sortie (et généralement, ils ne le font pas).
Notez également que les variables locales peuvent ne pas utiliser du tout d'espace de pile: elles peuvent être conservées dans les registres du processeur ou dans un autre emplacement de stockage auxiliaire, ou être entièrement optimisées.
Ainsi, le
d
tableau, en théorie, pourrait consommer de la mémoire pour toute la fonction. Cependant, le compilateur peut l'optimiser ou partager sa mémoire avec d'autres variables locales dont les durées d'utilisation ne se chevauchent pas.la source
Le temps pendant lequel la variable prend réellement de la mémoire dépend évidemment du compilateur (et de nombreux compilateurs n'ajustent pas le pointeur de pile lorsque des blocs internes sont entrés et sortis dans les fonctions).
Cependant, une question étroitement liée mais peut-être plus intéressante est de savoir si le programme est autorisé à accéder à cet objet interne en dehors de la portée interne (mais dans la fonction contenant), c'est-à-dire:
(En d'autres termes: le compilateur est-il autorisé à désallouer
d
, même si en pratique la plupart ne le font pas?).La réponse est que le compilateur est autorisé à désallouer
d
et à accéderp[0]
là où le commentaire indique un comportement indéfini (le programme n'est pas autorisé à accéder à l'objet interne en dehors de la portée interne). La partie pertinente de la norme C est 6.2.4p5:la source
Votre question n’est pas assez claire pour qu’on y réponde sans ambiguïté.
D'une part, les compilateurs ne font normalement aucune allocation-désallocation de mémoire locale pour les étendues de blocs imbriqués. La mémoire locale est normalement allouée une seule fois à l'entrée de la fonction et libérée à la sortie de la fonction.
En revanche, lorsque la durée de vie d'un objet local se termine, la mémoire occupée par cet objet peut être réutilisée ultérieurement pour un autre objet local. Par exemple, dans ce code
les deux tableaux occuperont généralement la même zone de mémoire, ce qui signifie que la quantité totale de stockage local nécessaire à la fonction
foo
est ce qui est nécessaire pour le plus grand des deux tableaux, pas pour les deux en même temps.d
C'est à vous de décider si ce dernier se qualifie comme continuant à occuper la mémoire jusqu'à la fin de la fonction dans le contexte de votre question.la source
Cela dépend de la mise en œuvre. J'ai écrit un petit programme pour tester ce que fait gcc 4.3.4, et il alloue tout l'espace de la pile à la fois au début de la fonction. Vous pouvez examiner l'assembly produit par gcc en utilisant l'indicateur -S.
la source
Non, d [] ne sera pas sur la pile pour le reste de la routine. Mais alloca () est différent.
Edit: Kristopher Johnson (et Simon et Daniel) ont raison , et ma réponse initiale était fausse . Avec gcc 4.3.4 sur CYGWIN, le code:
donne:
Vis et apprend! Et un test rapide semble montrer qu'AndreyT a également raison sur les allocations multiples.
Ajouté beaucoup plus tard : Le test ci-dessus montre que la documentation gcc n'est pas tout à fait correcte. Pendant des années, il a dit (italiques ajoutés):
la source
alloca
fonction. Je suis vraiment surpris que cygwin gcc fasse cela. Ce n'est même pas un tableau de longueur variable, donc IDK pourquoi vous en parlez.Ils pourraient. Peut-être pas. La réponse dont je pense que vous avez vraiment besoin est: ne supposez jamais rien. Les compilateurs modernes font toutes sortes d'architecture et de magie spécifique à l'implémentation. Écrivez votre code simplement et lisiblement aux humains et laissez le compilateur faire le bon travail. Si vous essayez de coder autour du compilateur, vous demandez des problèmes - et les problèmes que vous rencontrez habituellement dans ces situations sont généralement horriblement subtils et difficiles à diagnostiquer.
la source
Votre variable
d
n'est généralement pas sautée de la pile. Les accolades bouclées ne désignent pas un cadre de pile. Sinon, vous ne pourriez pas faire quelque chose comme ceci:Si les accolades provoquaient un véritable push / pop de pile (comme le ferait un appel de fonction), alors le code ci-dessus ne se compilerait pas car le code à l'intérieur des accolades ne serait pas en mesure d'accéder à la variable
var
qui vit en dehors des accolades (tout comme un sous- ne peut pas accéder directement aux variables de la fonction appelante). Nous savons que ce n’est pas le cas.Les accolades bouclées sont simplement utilisées pour la portée. Le compilateur traitera tout accès à la variable "interne" depuis l'extérieur des accolades englobantes comme invalide, et il pourra réutiliser cette mémoire pour autre chose (cela dépend de l'implémentation). Cependant, il ne peut pas être détaché de la pile avant le retour de la fonction englobante.
Mise à jour: voici ce que la spécification C a à dire. Concernant les objets à durée de stockage automatique (section 6.4.2):
La même section définit le terme «durée de vie» comme (c'est moi qui souligne):
Le mot clé ici est, bien entendu, «garanti». Une fois que vous quittez la portée de l'ensemble interne d'accolades, la durée de vie du tableau est terminée. Le stockage peut ou non lui être encore alloué (votre compilateur peut réutiliser l'espace pour autre chose), mais toute tentative d'accès au tableau invoque un comportement non défini et entraîne des résultats imprévisibles.
La spécification C n'a aucune notion de cadres de pile. Il ne parle que de la façon dont le programme résultant se comportera et laisse les détails de l'implémentation au compilateur (après tout, l'implémentation serait assez différente sur un processeur sans pile que sur un processeur avec une pile matérielle). Il n'y a rien dans la spécification C qui impose où un cadre de pile se terminera ou non. Le seul vrai moyen de le savoir est de compiler le code sur votre compilateur / plateforme particulier et d'examiner l'assembly résultant. L'ensemble actuel d'options d'optimisation de votre compilateur jouera probablement également un rôle à cet égard.
Si vous voulez vous assurer que le tableau
d
ne consomme plus de mémoire pendant l'exécution de votre code, vous pouvez convertir le code entre accolades en une fonction distincte ou explicitementmalloc
etfree
la mémoire au lieu d'utiliser le stockage automatique.la source
Je crois que cela sort du cadre, mais n'est pas sorti de la pile jusqu'à ce que la fonction retourne. Donc, il occupera toujours de la mémoire sur la pile jusqu'à ce que la fonction soit terminée, mais pas accessible en aval de la première accolade de fermeture.
la source
De nombreuses informations ont déjà été fournies sur la norme, indiquant qu'elle est effectivement spécifique à sa mise en œuvre.
Donc, une expérience pourrait être intéressante. Si nous essayons le code suivant:
En utilisant gcc on obtient ici deux fois la même adresse: Coliro
Mais si nous essayons le code suivant:
En utilisant gcc nous obtenons ici deux adresses différentes: Coliro
Donc, vous ne pouvez pas être vraiment sûr de ce qui se passe.
la source