Pourquoi les livres disent-ils, "le compilateur alloue de l'espace aux variables en mémoire"?

18

Pourquoi les livres disent-ils, "le compilateur alloue de l'espace aux variables en mémoire". N'est-ce pas l'exécutable qui fait ça? Je veux dire, par exemple, si j'écris le programme suivant,

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

et le compiler, et obtenir un exécutable (que ce soit program.exe), maintenant, si je lance program.exe, ce fichier exécutable commandera lui-même d'allouer de l'espace pour la variable foo. N'est-ce pas? Veuillez expliquer pourquoi les livres continuent de dire "le compilateur fera ceci ... fera cela".

Le codeur pacifique
la source
11
de quels livres parles-tu?
wirrbel
4
Votre «question connexe» devrait être une question distincte.
SShaheen
Le compilateur génère du code qui fait ceci ou c'est ce qu'ils disent. directement ou indirectement.
old_timer
FYI stackoverflow.com/questions/7372024/… et notez qu'un compilateur peut décider de changer l'emplacement d'une variable perçue en mémoire par souci d'alignement, par exemple: stackoverflow.com/questions/17774276/…
NoChance

Réponses:

20

Vous avez raison de dire que le compilateur en tant que tel a disparu lorsque votre programme s'exécute réellement. Et s'il s'exécute sur une autre machine, le compilateur n'est même plus disponible.

Je suppose que c'est pour faire une distinction claire entre la mémoire réellement allouée par votre propre code. Le compilateur insérera du code dans votre programme qui fait l'allocation de mémoire (comme en utilisant new, malloc ou des commandes similaires).

Les livres utilisent donc souvent "le compilateur fait ceci ou cela" pour dire que le compilateur a ajouté du code qui n'est pas explicitement mentionné dans vos fichiers de code. Il est vrai que ce n'est pas exactement ce qui se passe. De ce point de vue, beaucoup de choses mentionnées dans les tutoriels seraient erronées mais nécessiteraient des explications plutôt élaborées.

thorsten müller
la source
Oui, c'est ce que je croyais. Merci pour une réponse rapide!
The Peaceful Coder
12
le compilateur alloue la variable foo sur la pile en la substituant par un décalage au pointeur de pile lors de la compilation. Ce n'est pas du tout lié à l'allocation de tas qui est faite par mallocet. Al.
wirrbel
@holger: Votre objection est bien sûr techniquement correcte. Mais l'espace de pile en tant que tel doit toujours être alloué au démarrage du programme avant de pouvoir être utilisé (ce qui peut se produire de diverses manières, parfois en fonction de l'architecture du processeur). J'ai essayé de trouver des détails sur la façon dont cela se produit, mais sans grand succès.
thorsten müller
2
Je pense que la taille de la pile pour le thread principal est réservée par l'éditeur de liens, puis gérée par le système d'exploitation. Pour les threads personnalisés, elle est plus similaire à l'allocation de segments, c'est-à-dire que l'appelant peut fixer la taille lors de l'exécution.
wirrbel
4

Cela dépend de la variable. L'OS alloue le tas, le programme alloue la pile et le compilateur alloue de l'espace pour les globaux / statiques, c'est-à-dire qu'ils sont intégrés dans l'exe lui-même. Si vous allouez 1 Mo de mémoire globale, la taille de votre exe augmentera d'au moins 1 Mo

James
la source
1
Ce n'est pas de cela qu'il s'agit.
Philipp
2
en fait, il est plus proche de la question que les autres réponses énumérées ici.
wirrbel
@James Ah, ce n'est pas mon expérience. Par exemple, int test[256][1024]; int main(){ test[0][0]=2; return 0; } ce petit programme a 1 Mo alloué, mais ne me génère qu'un fichier objet de 1,4 Ko et un exécutable de 8,4 Ko. Il doit cependant utiliser la quantité de RAM appropriée.
Garet Claborn
1
Cela ne devrait-il pas être uniquement les commandes d'allocation stockées pour les globaux? Si vous avez codé en dur toutes les valeurs en utilisant les primitives comme int ou char, la taille de l'exécutable augmenterait certainement de plus que la quantité de variables ajoutées. Tels que int a1=1,a2=2,... tout le chemin vers ... , a1048576=1048576;Seulement alors, vous obtiendrez certainement quelque chose de plus grand que 1 Mo je pense.
Garet Claborn
2
C'est tout ce qui met les données dans la section BSS de l'exe
James
4

ce que le compilateur fera , c'est prendre votre code et le compiler en code machine. Ce que vous mentionnez est un bon exemple où un compilateur n'a besoin que de traduire.

Par exemple, lorsque vous écrivez

int foo;

Vous pouvez voir cela comme «je dis au compilateur de [ dans la sortie qu'il génère ] demander que l'ordinateur réserve suffisamment de RAM pour un int que je puisse référencer plus tard. Le compilateur utilisera probablement un identifiant de ressource ou un mécanisme pour suivre foo dans le code machine, vous pouvez utiliser foo dans un fichier texte au lieu d'écrire l'assemblage! Vive !

Vous pouvez donc également examiner cela lorsque le compilateur écrit une lettre ( ou peut-être un roman / une encyclopédie ) à tous les processeurs et périphériques ciblés. La lettre est écrite en signaux binaires qui (généralement) peuvent être traduits vers différents processeurs en changeant la cible. N'importe quelle «lettre» et / ou combo peut envoyer toutes sortes de requêtes et / ou de données - veuillez allouer de l'espace pour cette variable que le programmeur a utilisée.

Garet Claborn
la source
3

Dire «le compilateur alloue de la mémoire» peut ne pas être exact dans les faits au sens littéral, mais c'est une métaphore qui est suggestive dans le bon sens.

Ce qui se passe vraiment, c'est que le compilateur crée un programme qui alloue sa propre mémoire. Sauf que ce n'est pas le programme qui alloue la mémoire, mais le système d'exploitation.

Donc, ce qui se passe vraiment, c'est que le compilateur crée un programme qui décrit ses besoins en mémoire et que le système d'exploitation prend cette description et l'utilise pour allouer de la mémoire. Sauf que l'OS est un programme et que les programmes ne font rien, ils décrivent un calcul effectué par le CPU. Sauf que le CPU n'est vraiment qu'un circuit électronique compliqué, pas un petit homonculus anthropomorphisé.

Mais il est logique de considérer les programmes et les compilateurs et les processeurs comme de petites personnes qui vivent à l'intérieur d'un ordinateur, non pas parce qu'ils le sont réellement, mais parce que c'est une métaphore qui convient bien au cerveau humain.

Certaines métaphores fonctionnent bien pour décrire les choses à un niveau d'abstraction, mais ne fonctionnent pas aussi bien à un autre niveau. Si vous pensez au niveau du compilateur, il est logique de décrire l'acte de générer du code qui entraînera l'allocation de mémoire lorsque le programme en cours de compilation est en fait exécuté comme "allocation de mémoire". Il est suffisamment proche pour que lorsque nous réfléchissons au fonctionnement d'un compilateur, nous ayons la bonne idée, et ce n'est pas si long que nous oublions ce que nous faisions. Si nous essayons d'utiliser cette métaphore au niveau du programme compilé en cours d'exécution, c'est trompeur d'une manière étrange, ce que vous avez remarqué.

Michael Shaw
la source
0

C'est le compilateur qui décide où stocker une variable - peut être dans la pile ou dans un registre gratuit. Quelle que soit la décision de stockage prise par le compilateur, le code machine correspondant pour accéder à cette variable sera généré et ne pourra pas être modifié lors de l'exécution. En ce sens, le compilateur est en charge d'allouer de l'espace aux variables et le programme final.exe agit simplement à l'aveuglette comme un zombie au moment de l'exécution.

Maintenant, ne confondez pas cela avec une gestion de mémoire dynamique différente comme malloc, new ou peut être votre propre gestion de mémoire. Les compilateurs traitent du stockage et de l'accès variables, mais peu importe ce que signifie une valeur réelle dans un autre framework / bibliothèque. Par exemple:

byte* pointer = (byte*)malloc(...);

Au moment de l'exécution, malloc peut renvoyer un nombre arbitraire, mais le compilateur s'en fiche, tout ce qui lui importe, c'est où stocker ce numéro.

Codisme
la source
0

Une formulation plus précise serait: - "le compilateur dit au chargeur de réserver de l'espace pour les variables"

Dans un environnement C-ish, il y aura trois types d'espace pour les variables: -

  • un bloc fixe pour les variables statiques
  • Un grand bloc pour les variables "automatiques", généralement appelé "pile". Les fonctions saisissent un morceau à l'entrée et le libèrent au retour.
  • Un grand bloc appelé "tas", à partir duquel la mémoire gérée par le programme est allouée (à l'aide de malloc () ou d'une API de gestion de la mémoire similaire.

Sur un système d'exploitation moderne, la mémoire du tas ne sera pas réellement réservée mais allouée selon les besoins.

James Anderson
la source
0

Oui, vous avez raison, dans ce cas (en déclarant une variable dans une fonction), la phrase de votre livre est probablement incorrecte: lorsque vous déclarez une variable dans une fonction, elle est allouée sur la pile lors de l'entrée dans la fonction. Quoi qu'il en soit, un compilateur devrait optimiser la situation: si la fonction est non récursive ( main()est un bon candidat pour elle), il est OK de "l'allouer" au moment de la compilation (sur le BSS).

(Si vous êtes curieux de savoir où résident vos variables, vous pouvez le vérifier de manière sale (si vous ne voulez pas examiner la structure du fichier obj, de toute façon, pourquoi pas?), Vous pouvez donc déclarer différents types de variables: constantes, statiques, dynamiques, malloc()allouées, etc. et afficher leurs adresses (utilisez le %Xformateur printf()pour une meilleure lisibilité). Les variables résidant sur la pile auront des adresses mémoire très différentes.)

ern0
la source
0

La seule chose à faire au moment de l'exécution sera de déplacer le pointeur de pile d'un certain montant. Le compilateur décide donc à l'avance:

  • combien d'espace de pile sera nécessaire pour la fonction.
  • À quel décalage du pointeur de pile chaque variable individuelle sera localisée.

Celui-ci peut être appelé "allocation", mais bien sûr, pendant la compilation, il ne prend place que dans le modèle que le compilateur a du programme en cours d'exécution.

Ingo
la source