155 votes

Dans C, les accolades agissent-elles comme un cadre de pile?

Si je crée une variable dans un nouvel ensemble d'accolades, est-ce que cette variable est 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;
}
 

Est-ce que d prendra de la mémoire pendant la section code that takes a while ?

84voto

Kristopher Johnson Points 34554

Non, les accolades n’agissent pas comme un frame de pile. En C, accolades indiquent seulement une portée de désignation, mais rien ne se détruit lorsque le contrôle passe hors de lui.

Ainsi, le `` tableau, en théorie, pourrait consommer de la mémoire pour la fonction entière. Toutefois, le compilateur peut optimiser loin ou partager sa mémoire avec d’autres variables locales si leur utilisation ne se chevauche pas.

41voto

caf Points 114951

Le temps pendant lequel la variable est en fait de prendre de la mémoire est évidemment compilateur-dépendante (et de nombreux compilateurs ne pas ajuster le pointeur de pile, lorsque les blocages intérieurs, sont entrés et sortis à l'intérieur des fonctions).

Cependant, étroitement liés, mais peut-être plus question intéressante est de savoir si le programme est autorisé à accéder intérieur de l'objet à l'extérieur de l'intérieur de la portée (mais à l'intérieur de la fonction contenante), c'est à dire:

void foo() {
   int c[100];
   int *p;

   {
       int d[200];
       p = d;
   }

   /* Can I access p[0] here? */

   return;
}

(En d'autres mots: est-ce que le compilateur a permis de libérer d, même si dans la pratique, la plupart ne le font pas?).

La réponse est oui, le compilateur est autorisé à libérer d, et d'accéder p[0] où le commentaire indique, est un comportement indéterminé. La partie pertinente de la norme C est 6.2.4p5:

Pour un tel objet [celui qui a automatique de la durée de stockage] qui ne ne pas avoir une longueur variable de type tableau, sa durée de vie s'étend de l'entrée dans le bloc auquel il est associé jusqu'à l'exécution de ce bloc se termine dans de toute façon. (La saisie d'un joint de bloc ou l'appel d'une fonction suspend, mais n'a pas de fin, de l'exécution du présent le bloc.) Si le bloc est entré de manière récursive, une nouvelle instance de la l'objet est créé à chaque fois. L' valeur initiale de l'objet est durée indéterminée. Si une initialisation défini pour l'objet, c'est effectué à chaque fois que la déclaration est atteint dans l'exécution du bloc; sinon, la valeur devient indéterminée à chaque fois que l' la déclaration est atteint.

21voto

AndreyT Points 139512

Votre question n'est pas suffisamment claire pour être répondu sans ambiguïté.

D'une part, les compilateurs n'ont pas l'habitude de faire toute la mémoire locale de répartition de libération de la mémoire pour les sous domaines de bloc. La mémoire locale est normalement attribuée qu'une seule fois à l'entrée de la fonction et publié lors de la sortie de la fonction.

D'autre part, lorsque la durée de vie d'un objet local se termine, la mémoire occupée par l'objet peut être réutilisé pour un autre objet plus tard. Par exemple, dans ce code

void foo()
{
  {
    int d[100];
  }
  {
    double e[20];
  }
}

les deux tableaux habituellement occupent la même zone de mémoire, ce qui signifie que le montant total de la local de stockage requis par la fonction foo est tout ce qui est nécessaire pour le plus grand des deux tableaux, et pas pour les deux en même temps.

Si ce dernier qualifie d de continuer à occuper la mémoire jusqu'à la fin de la fonction dans le contexte de votre question, c'est à vous de décider.

6voto

Daniel Stutzbach Points 20026

C' est application dépendante. J’ai écrit un programme court pour tester ce que gcc 4.3.4 fait, et qu’il alloue de l’espace de pile à la fois au début de la fonction. Vous pouvez examiner l’Assemblée que gcc produit utilisant l’option -S.

3voto

Joseph Quinsey Points 4450

Non, d[] va pas être sur la pile pour le reste de la routine. Mais alloca() est différent.

Edit: Kristopher Johnson (simon et Daniel) sont à droite, et ma première réaction a été de mal. Avec gcc 4.3.4.sur CYGWIN, le code:

void foo(int[]);
void bar(void);
void foobar(int); 

void foobar(int flag) {
    if (flag) {
        int big[100000000];
        foo(big);
    }
    bar();
}

donne:

_foobar:
    pushl   %ebp
    movl    %esp, %ebp
    movl    $400000008, %eax
    call    __alloca
    cmpl    $0, 8(%ebp)
    je      L2
    leal    -400000000(%ebp), %eax
    movl    %eax, (%esp)
    call    _foo
L2:
    call    _bar
    leave
    ret

Vivre et apprendre! Et un test rapide semble montrer que AndreyT est également correcte sur plusieurs allocations.

Ajouté beaucoup plus tard: Le test ci-dessus montre la gcc de la documentation n'est pas tout à fait droit. Pendant des années il a dit (italiques ajoutés):

"L'espace d'une longueur variable tableau est libéré dès que le nom de la baie du champ d'application se termine."

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X