106 votes

La pile grandit-elle vers le haut ou vers le bas?

J'ai ce bout de code en c:

int q=10; int s=5; int a[3];

printf("Address of a: %d\n",(int)a);
printf("Address of a[1]: %d\n",(int)&a[1]);
printf("Address of a[2]: %d\n",(int)&a[2]);
printf("Address of q: %d\n",(int)&q);
printf("Address of s: %d\n",(int)&s);

La sortie est:

Address of a: 2293584
Address of a[1]: 2293588
Address of a[2]: 2293592
Address of q: 2293612
Address of s: 2293608

Donc, je vois que d'un point a à un[2], les adresses mémoire augmente de 4 octets chacun. Mais à partir de q à s, des adresses mémoire, diminution de 4 octets.

Je me demande 2 choses:

  1. N'pile de croître vers le haut ou vers le bas? (Il ressemble à la fois pour moi dans ce cas)
  2. Ce qui se passe entre un[2] et q des adresses de mémoire? Pourquoi il y a un gros mémoire différence il y a? (20 octets).

Remarque: Ce n'est pas de devoirs question. Je suis curieux sur la façon dont la pile fonctionne. Merci pour toute aide.

88voto

Le comportement de la pile (à grandir ou à la culture du bas) dépend de l'application binary interface (ABI) et comment la pile d'appel (aka l'activation de l'enregistrement) est organisé.

Tout au long de sa durée de vie un programme est lié à communiquer avec d'autres programmes comme les OS. ABI détermine comment un programme peut communiquer avec un autre programme.

La pile pour les différentes architectures peuvent croître à l'une ou l'autre manière, mais d'une architecture il sera compatible. Veuillez consulter ce lien wiki. Mais, la pile de la croissance est décidé par l'ABI de cette architecture.

Par exemple, si vous prenez le MIPS ABI, la pile d'appel est défini comme ci-dessous.

Permettez-nous de considérer que la fonction " fn1 "appels " fn2'. Maintenant, la trame de pile comme on le voit par " fn2 " est comme suit:

direction of     |                                 |
  growth of      +---------------------------------+ 
   stack         | Parameters passed by fn1(caller)|
from higher addr.|                                 |
to lower addr.   | Direction of growth is opposite |
      |          |   to direction of stack growth  |
      |          +---------------------------------+ <-- SP on entry to fn2
      |          | Return address from fn2(callee) | 
      V          +---------------------------------+ 
                 | Callee saved registers being    | 
                 |   used in the callee function   | 
                 +---------------------------------+
                 | Local variables of fn2          |
                 |(Direction of growth of frame is |
                 | same as direction of growth of  |
                 |            stack)               |
                 +---------------------------------+ 
                 | Arguments to functions called   |
                 | by fn2                          |
                 +---------------------------------+ <- Current SP after stack 
                                                        frame is allocated

Maintenant, vous pouvez voir la pile grandit vers le bas. Donc, si les variables sont allouées pour le repère local de la fonction de la variable adresses pousse réellement à la baisse. Le compilateur peut décider de l'ordre des variables pour l'allocation de mémoire. (Dans votre cas, il peut être 'q' ou 's' qui est d'abord affecté de la pile mémoire. Mais, en général, le compilateur ne la pile d'allocation de mémoire selon l'ordre de la déclaration des variables).

Mais dans le cas des tableaux, la répartition seul pointeur et la mémoire a besoin d'être allouée sera effectivement pointé par un seul pointeur. La mémoire a besoin d'être contigus pour un tableau. Donc, si la pile grandit vers le bas, pour les tableaux de la pile grandit.

49voto

Crashworks Points 22920

C'est en fait deux questions. On est sur le chemin de la pile grandit quand une fonction en appelle une autre (lorsqu'une nouvelle image est affecté), et l'autre est à propos de la manière dont les variables sont définies dans une fonction particulière de l'image.

Ni est spécifié par la norme, mais les réponses sont un peu différentes:

  • Comment la pile augmente lorsqu'une nouvelle image est affecté -- si la fonction f() appelle la fonction g(), fs'pointeur de l'image plus ou moins de gs'pointeur de l'image? Cela peut aller de toute façon -- il dépend du compilateur et de l'architecture ("convention d'appel"), mais il est toujours cohérents au sein d'une plate-forme donnée (avec un peu bizarres exceptions, voir les commentaires). La baisse est plus fréquente; c'est le cas dans les architectures x86, PowerPC, MIPS, SPARC, EE, et la Cellule SPUs.
  • Comment sont locale d'une fonction des variables définies à l'intérieur de son cadre de pile? Ce n'est pas spécifié et complètement imprévisible; le compilateur est libre d'organiser ses variables locales cependant, il aime faire le plus de résultat efficace.

16voto

R Samuel Klatchko Points 44549

La direction est que les piles se développent est spécifique à l'architecture. Cela dit, si j'ai bien compris, seules quelques rares architectures matérielles ont des piles grandissantes.

La direction dans laquelle une pile grandit est indépendante de la disposition d'un objet individuel. Ainsi, bien que la pile puisse grandir, les tableaux ne le seront pas (c'est-à-dire & array [n] sera toujours <& array [n + 1]);

6voto

paxdiablo Points 341644

Il n'y a rien dans la norme que les mandats comment les choses sont organisées sur la pile. En fait, vous pourriez construire un compilateur conforme qui n'a pas stocker les éléments du tableau à contiguë éléments sur la pile à tous, pourvu qu'il ait l'intelligence de toujours l'élément de tableau arithmétique correctement (alors qu'elle savait, par exemple, qu'un[1] a été 1K loin de a[0] et pourrait ajuster pour que).

La raison pour laquelle vous pouvez obtenir des résultats différents est parce que, tandis que la pile peut pousser vers le bas pour ajouter des "objets", le tableau est un "objet" unique et il peut en avoir l'ascendant des éléments d'un tableau dans l'ordre inverse. Mais il n'est pas sûr de s'appuyer sur ce comportement depuis la direction peut changer et les variables peuvent être échangées autour pour une variété de raisons, y compris, mais non limité à:

  • l'optimisation.
  • l'alignement.
  • les caprices de la personne la gestion de la pile du compilateur.

Voir ici pour mon excellent traité sur la pile de direction :-)

En réponse à vos questions spécifiques:

  1. N'pile de croître vers le haut ou vers le bas?
    Il n'a pas d'importance (en termes de la norme), mais, puisque vous le demandez, il peut grandir ou vers le bas dans la mémoire, en fonction de la mise en œuvre.
  2. Ce qui se passe entre un[2] et q des adresses de mémoire? Pourquoi il y a une grande mémoire différence il y a? (20 octets)?
    Il n'a pas d'importance (en termes de la norme). Voir ci-dessus pour les raisons possibles.

3voto

rmeador Points 15107

Sur un système x86, la mémoire "attribution" d'un cadre de pile consiste simplement en soustrayant le nombre d'octets nécessaire de le pointeur de pile (je crois que d'autres architectures sont similaires). En ce sens, je suppose que la pile growns "vers le bas", en ce que les adresses obtenir progressivement plus petites, comme vous l'appelez plus profondément dans la pile (mais j'ai toujours envisager la mémoire à partir de 0 en haut à gauche et à obtenir plus d'adresses que vous le déplacez vers la droite et le point de conclure, donc, à mon image mentale de la pile grandit...). L'ordre des variables déclarées ne peut pas avoir une incidence sur leurs adresses -- je crois que la norme permet au compilateur de les réorganiser, tant qu'il ne cause pas d'effets secondaires (quelqu'un s'il vous plaît corrigez-moi si je me trompe). Ils sont juste coincé quelque part dans cette lacune dans les adresses utilisées créé lorsqu'il soustrait le nombre d'octets à partir du pointeur de pile.

L'écart autour de la matrice peut être une sorte de rembourrage, mais c'est mystérieux pour moi.

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