Pourquoi les livres disent-ils: "Le compilateur alloue de l'espace pour les variables en mémoire". N'est-ce pas l'exécutable qui fait cela? Je veux dire, par exemple, si j'écris le programme suivant,
#include <iostream> using namespace std; int main() { int foo = 0; cout<<foo; return 0; }
7 Réponses :
Il indique que le compilateur alloue de l'espace pour des variables en mémoire, car vous devez également allouer (et libre!) Memory vous-même avec Nouveau / MALLOC CODE> ETC. P>
Et ce ne sera pas compilateur alors? Vous allez juste l'écrire sur un morceau de papier? ; p
C'est juste une utilisation en vrac de terminologie. Bien sûr, le compilateur n'alloue pas la mémoire du programme. Une description plus précise est qu'elle indique à l'exécution combien de mémoire allouer lorsque le programme est en cours d'exécution. P>
Jusqu'à ce que le programme soit réellement exécuté, ce n'est pas en mémoire (à moins que cela ne soit chargé de manière dynamique, mais même cela se produise pendant la période d'exécution, donc hors de la portée du compilateur), il n'y a donc pas de mémoire à parler. < / p>
Qu'est-ce que ces livres parlent d'allouer des variables dont la taille est connue au moment de la compilation, par opposition à une allocation dynamique Cin >> x; int * y = nouveau [x]; code>, où la taille n'est pas connue. p>
Techniquement, l'acte de créer l'espace lui-même est effectué au moment de l'exécution, mais le compilateur est celui de déterminer combien d'espace pour réserver em> sur la pile dans votre cas, pour votre Le compilateur connaît la taille du type Si vous regardez l'assembleur généré ci-dessous (en utilisant MSVC2012) pour le programme que vous avez montré, j'ai commenté certains d'entre eux pour vous montrer ce qui se passe: P> FOO code> variable.
int code> et peut donc générer l'instruction d'assembleur de droite qui réserver suffisamment d'espace sur la pile afin de laisser
foo code> en direct. p>
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
//Setup stack frame for main by storing the stack pointer from the calling function and
//reserving space for local variables and storing commonly used registers on the stack
002E4390 push ebp
002E4391 mov ebp,esp
// reserve space for local variables, which is 204 bytes here, no idea why so much.
// this is where the compiler calculated the size of your foo and added that to whatever else needs to be stored on the stack. Subtract from stack pointer (esp) because stack grows downward.
002E4393 sub esp,0CCh
002E4399 push ebx
002E439A push esi
002E439B push edi
002E439C lea edi,[ebp-0CCh] // load effective address of [ebp-0CCh], which I suspect would be your foo variable into edi register
002E43A2 mov ecx,33h
002E43A7 mov eax,0CCCCCCCCh
002E43AC rep stos dword ptr es:[edi] //fill block of memory at es:[edi] with stuff
int foo;
return 0;
002E43AE xor eax,eax //set eax to zero for return value
}
// restore everything back to how it was before main was called
002E43B0 pop edi
002E43B1 pop esi
002E43B2 pop ebx
002E43B3 mov esp,ebp
002E43B5 pop ebp
002E43B6 ret
Une question intéressante ici est la raison pour laquelle le compilateur alloue 204 octets pour les variables locales, lorsque tout ce dont il a besoin est 4. (Vous avez utilisé VC ++ ici, mais j'ai remarqué plusieurs compilateurs qui semblent allouer beaucoup plus que nécessaire.)
@Jameskanze, je me suis demandé ça. Je ne suis pas sûr de savoir pourquoi il semble allouer beaucoup.
@Jameskanze j'ai posé une question demandant ceci: Stackoverflow.com/questions/15806673/... parce que je suis curieux de savoir pourquoi cela serait. Je t'ai mentionné
@Tony the Lion merci à l'homme, votre réponse montre des efforts. Eh bien, je voulais juste vous demander, comment comprenez-vous ces instructions d'assembleur? Faut-il la connaissance de la langue d'assemblage? Si oui, veuillez me suggérer un bon livre pour apprendre la langue de montage depuis le début. Merci encore!
@Rage Oui, j'ai passé du temps dans le passé apprenant l'assembleur de base.
@ABYX Je pense que pour montrer ce qui se passe dans ce cas, ce n'est pas vraiment important.
@Tonythelion La sortie de montage que vous avez fournie n'a rien à voir avec le code source. {int foo; Retour 0;} code> doit être compilé sous forme
renvoyer 0; code>, sans variables locales. Il vient de arriver que votre compilateur a injecté beaucoup d'autres instructions.
@Abyx il vous manque le point. Complètement. L'idée était de décrire à l'OP comment le compilateur génère l'assemblage qui décrit les exigences de la mémoire d'un programme donné. Pas le spécifique, ni pour décrire les possibilités d'optimisation et les approches.
Lorsque nous embauchons un architecte pour concevoir une maison, il définit la taille des chambres, etc. et informe les travailleurs (ouvriers) à ce sujet. Les ouvriers font le travail en conséquence. Mais nous dirions toujours " l'architecte a fait la maison de cette façon em>" et L'ouvrier n'effectue que les étapes définies par l'architecte. Le compilateur effectue en réalité tout le travail de vérification et de définition de la quantité de mémoire à attribuer, etc. au moment de l'exécution, puis ces instructions sont simplement suivies. P>
Compilateur de cours ne "allège pas d'espace pour les variables". Compilateur génère un code qui attribue l'espace pour les variables en mémoire.
I.e. Si vous avez p> dans le code source, le compilateur peut générer un code comme p> dans l'architecture x86, généralement que Si vous avez plus d'une variable locale, le compilateur les emballera dans une structure et les allouera Ensemble: p> sera compilé comme p> ou p> allouer code> chose sera une seule instruction d'assemblage: p>
Vous suggère de lire la construction du compilateur. Concentrez-vous sur la phase de stockage, votre requête serait résolue. p>
Une fois que le programme est compilé son converti en code d'objet, qui est un code de langue d'assemblage. Chaque ligne d'un programme de langue de haut niveau se traduit par de nombreuses étapes de la langue d'assemblage. Le programme traduit est mis dans l'assembleur qui est exécuté. Il existe une phase d'affectation de stockage dans la construction de Comiler qui se traduit par la table de fonctionnement de la machine (instructions MOT au niveau de montage). C'est là que la répartition spatiale pour les variables / registres est terminée. Il existe un mot-clé de modificateur de registre en C ++. P>
Cela ne fournit pas de réponse à la question. Pour critiquer ou demander des éclaircissements d'un auteur, laissez un commentaire sous leur poste - vous pouvez toujours commenter vos propres messages, et une fois que vous avez suffisamment Réputation Vous pourrez Commentaire sur n'importe quel message .
Une fois que le programme est compilé son converti en code d'objet, qui est un code de langue d'assemblage. Chaque ligne d'un programme de langue de haut niveau se traduit par de nombreuses étapes de la langue d'assemblage. Le programme traduit est mis dans l'assembleur qui est exécuté. Il existe une phase d'affectation de stockage dans la construction de Comiler qui se traduit par la table de fonctionnement de la machine (instructions MOT au niveau de montage). C'est là que la répartition spatiale pour les variables / registres est terminée. Il existe un mot-clé de modificateur de registre en C ++.
Je connais Nico O .. Veuillez demander de clarté dans les commentaires des utilisateurs si vous ne comprenez pas la réponse / la perspective des autres. Une fois que l'auteur est conscient du processus de construction du compilateur, il comprendra c'est son code d'objet qui fonctionne. COMPILER est un simple générateur de code vers le niveau de code de programmation inférieur.
-1. Ce que vous dites n'a rien à voir avec la question. Cela s'applique aussi aux commentaires.
Le compilateur génère des instructions sur la machine et fonctionne de l'adressage de la mémoire Variables locales occupera. Chaque variable locale reçoit une adresse relative au sommet de la pile, par exemple Lorsque la variable locale Le compilateur sait quelle taille chaque variable est qu'elle est responsable de la recherche sur foo code> serait supposé être à l'adresse de la mémoire
stack_pointer code>. Si vous aviez une variable
FOO2 code>, il serait placé à l'adresse
stack_pointer + 4 code> où 4 est la taille d'un
int code>. p>
FOO code> est accessible, le compilateur substituera l'adresse détenue dans
stack_packer code>. Le matériel dispose d'un enregistrement spécial
stack_pointer code> qui pointe toujours vers le haut de la pile en cours. P>
struct code> ou
des déclarations code> et de savoir comment il est aménagé en mémoire. Donc,
Tailleof code> est connu au moment de la compilation et est traité comme une expression constante. Les types primitifs tels que
int code> sont connus d'une certaine taille, par exemple
Tailleof (int) code> est 4. P>
C'est un mauvais exemple.
FOO code> n'est pas utilisé et sera éliminé pendant la compilation.
@Abyx Man, essayez de comprendre ma question. L'accent n'est pas mis sur si le Var est utilisé. Quoi qu'il en soit, j'ai édité le programme pour vous.
Homme, rien n'a changé avec cette modification. =)