Por que os livros dizem: "o compilador aloca espaço para variáveis ​​na memória"?


18

Por que os livros dizem "o compilador aloca espaço para variáveis ​​na memória". Não é o executável que faz isso? Quero dizer, por exemplo, se eu escrever o seguinte programa,

#include <iostream>
using namespace std;

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

compile-o e obtenha um executável (que seja program.exe), agora, se eu executar o programa.exe, esse arquivo executável comandará ele próprio para alocar algum espaço para a variável foo. Não é? Por favor, explique por que os livros continuam dizendo: "o compilador fará isso ... fará aquilo".


11
de quais livros você está falando?
Wirrbel #

4
Sua "pergunta relacionada" deve ser uma pergunta separada.
SShaheen


O compilador gera código que faz isso ou aquilo é o que eles estão dizendo. diretamente ou indiretamente.
old_timer

FYI stackoverflow.com/questions/7372024/… e observe que um compilador pode decidir alterar a localização de uma variável percebida na memória para fins de alinhamento, por exemplo: stackoverflow.com/questions/17774276/…
NoChance

Respostas:


20

Você está certo de que o compilador desapareceu quando o seu programa realmente é executado. E se for executado em uma máquina diferente, o compilador não estará mais disponível.

Eu acho que isso é para fazer uma distinção clara entre a memória realmente alocada pelo seu próprio código. O compilador inserirá algum código no seu programa que faz a alocação de memória (como o uso de comandos new, malloc ou similares).

Portanto, os livros usam "o compilador faz isso ou aquilo" frequentemente para dizer que o compilador adicionou algum código que não é mencionado explicitamente nos seus arquivos de código. É verdade que isso não é exatamente o que está acontecendo. Desse ponto de vista, muitas coisas mencionadas nos tutoriais estariam erradas, mas precisariam de explicações bastante elaboradas.


Sim, era nisso que eu acreditava. Obrigado por uma resposta rápida!
The Peaceful Coder

12
o compilador aloca a variável foo na pilha, substituindo-a por um deslocamento no ponteiro da pilha durante a compilação. Não tem nada a ver com a alocação de heap, feita por mallocet. al.
Wirrbel #

@ holger: Sua objeção é tecnicamente correta, é claro. Mas o espaço de pilha, como tal, ainda deve ser alocado quando o programa é iniciado antes de ser usado (o que pode ocorrer de várias maneiras, às vezes dependendo da arquitetura da CPU). Tentei encontrar alguns detalhes de como isso acontece, mas sem muito sucesso.
thorsten Müller

2
Eu acho que o tamanho da pilha para o thread principal é reservado pelo vinculador e depois tratado pelo sistema operacional. Para threads personalizados, é mais semelhante à alocação de heap, ou seja, o chamador pode corrigir o tamanho no tempo de execução.
Wirrbel #

4

Depende da variável. O sistema operacional aloca heap, o programa aloca pilha e o compilador aloca espaço para globais / estáticos, ou seja, eles são construídos no próprio exe. Se você alocar 1 MB de memória global, o tamanho do seu exe aumentará em pelo menos 1 MB


1
Não é disso que se trata esta questão.
Philipp

2
na verdade, está mais próximo da pergunta do que das outras respostas listadas aqui.
Wirrbel #

@ James Ah, esta não é a minha experiência. Por exemplo: int test[256][1024]; int main(){ test[0][0]=2; return 0; } Este pequeno programa possui 1 MB alocado, mas só me gera um arquivo de objeto de 1,4 Kb e um executável de 8,4 Kb. Ele deve usar a quantidade correta de RAM, no entanto.
amigos estão dizendo sobre garet claborn

1
Não deveriam ser apenas os comandos de alocação armazenados para globais? Se você codificou todos os valores usando as primitivas como int ou char, o tamanho do executável aumentaria definitivamente mais do que a quantidade de variáveis ​​adicionadas. Tais como int a1=1,a2=2,... todo o caminho até ... , a1048576=1048576;Só então você definitivamente obteria algo maior que 1mb, eu acho.
amigos estão dizendo sobre garet claborn

2
É o que quer que coloca os dados na seção BSS da exe
James

4

o que o compilador fará é pegar seu código e compilá-lo no código da máquina. O que você mencionou é um bom exemplo em que um compilador precisa apenas traduzir.

Por exemplo, quando você escreve

int foo;

Você pode ver isso como 'Estou dizendo ao compilador para [ na saída que ele gera ] solicitar que o computador reserve RAM suficiente para um int que eu possa referenciar mais tarde. O compilador provavelmente usará uma identificação de recurso ou algum mecanismo para rastrear o foo no código de máquina, você pode usar foo em um arquivo de texto em vez de escrever a montagem! Viva !

Portanto, você também pode olhar para isso, pois o compilador está escrevendo uma carta ( ou talvez uma novela / enciclopédia ) para todos os processadores e dispositivos de destino. A carta é escrita em sinais binários que (geralmente) podem ser traduzidos para diferentes processadores alterando o destino. Qualquer 'carta' e / ou combinação pode estar enviando todos os tipos de solicitações e / ou dados - como, por favor, aloque espaço para essa variável que o programador usou.


3

Dizer "o compilador aloca memória" pode não ser factualmente preciso no sentido literal, mas é uma metáfora sugestiva da maneira correta.

O que realmente acontece é que o compilador cria um programa que aloca sua própria memória. Exceto que não é o programa que aloca memória, mas o sistema operacional.

Então, o que realmente acontece é que o compilador cria um programa que descreve seus requisitos de memória e o sistema operacional pega essa descrição e a usa para alocar memória. Exceto que o sistema operacional é um programa e os programas realmente não fazem nada, eles descrevem uma computação executada pela CPU. Exceto que a CPU é realmente apenas um circuito eletrônico complicado, não um homônculo antropomorfizado.

Mas faz sentido pensar em programas, compiladores e CPUs como pessoas pequenas que vivem dentro de um computador, não porque realmente são, mas porque essa é uma metáfora que se encaixa bem no cérebro humano.

Algumas metáforas funcionam bem para descrever as coisas em um nível de abstração, mas não funcionam tão bem em outro nível. Se você pensa no nível do compilador, faz sentido descrever o ato de gerar código que resultará na alocação de memória quando o programa que está sendo compilado for realmente executado como "alocação de memória". É perto o suficiente para que, quando pensemos em como um compilador funcione, tenhamos a idéia certa e não demore tanto tempo para esquecermos o que estávamos fazendo. Se tentarmos usar essa metáfora no nível do programa compilado em execução, ela será enganosa de uma maneira estranha, e foi o que você notou.


0

É o compilador que decide onde armazenar uma variável - pode estar na pilha ou em um registro gratuito. Qualquer que seja a decisão de armazenamento tomada pelo compilador, o código de máquina correspondente para acessar essa variável será gerado e não poderá ser alterado em tempo de execução. Nesse sentido, o compilador é responsável por alocar espaço para as variáveis ​​e o program.exe final está agindo cegamente como um zumbi em tempo de execução.

Agora, não confunda isso com gerenciamento de memória dinâmica diferente, como malloc, novo ou pode ser seu próprio gerenciamento de memória. Os compiladores estão lidando com armazenamento e acesso variáveis, mas não se importa com o que um valor real significa em outra estrutura / biblioteca. Por exemplo:

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

Em tempo de execução, o malloc pode retornar um número arbitrário, mas o compilador não se importa, tudo o que importa é onde armazenar esse número.


0

Uma frase mais precisa seria: - "o compilador diz ao carregador para reservar espaço para as variáveis"

Em um ambiente C-ish, haverá três tipos de espaço para variáveis: -

  • um bloco fixo para variáveis ​​estáticas
  • Um bloco grande para variáveis ​​"automáticas" geralmente chamadas de "pilha". As funções agarram um pedaço na entrada e soltam-no no retorno.
  • Um bloco grande chamado "heap", onde é alocada a memória gerenciada pelo programa (usando malloc () ou API de gerenciamento de memória semelhante.

Em um sistema operacional moderno, a memória heap não será realmente reservada, mas alocada conforme necessário.


0

Sim, você está certo, neste caso (declarando uma variável em uma função), a frase do seu livro provavelmente está incorreta: quando você declara uma variável em uma função, ela é alocada na pilha ao entrar na função. De qualquer forma, um compilador deve otimizar a situação: se a função não for recursiva ( main()é uma boa candidata a ela), não há problema em "alocar" o tempo de compilação (no BSS).

(Se você está curioso sobre onde suas variáveis ​​residem, você pode verificá-lo de maneira suja (se você não quiser examinar a estrutura do arquivo obj, por que não?), Para poder declarar alguns tipos diferentes de variáveis: constant, estático, dinâmico, malloc()alocado etc., e exibe seus endereços (use o %Xformatador printf()para melhor legibilidade) .As variáveis ​​que residem na pilha terão endereços de memória muito diferentes.


0

A única coisa feita em tempo de execução será aumentar o poinbter da pilha em uma certa quantidade. Portanto, o compilador decide de antemão:

  • quanto espaço de pilha será necessário para a função.
  • A que deslocamento do ponteiro da pilha cada variável individual será localizada.

Esse pode ser chamado de "alocação", mas é claro, durante o tempo de compilação, ele ocupa apenas o modelo que o compilador possui do programa em execução.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.