Considerando que a memória é dividida em quatro segmentos: dados, pilha, pilha e código, onde variáveis globais, variáveis estáticas, tipos de dados constantes, tipos de dados constantes, variáveis locais (definidas e declaradas em funções), variáveis (na função principal), ponteiros e o espaço alocado dinamicamente (usando malloc e calloc) são armazenados na memória?
Eu acho que eles seriam alocados da seguinte forma:
- Variáveis globais -------> dados
- Variáveis estáticas -------> dados
- Tipos de dados constantes -----> código
- Variáveis locais (declaradas e definidas em funções) --------> stack
- Variáveis declaradas e definidas na função principal -----> heap
- Ponteiros (por exemplo
char *arr
,int *arr
) -------> heap - Espaço alocado dinamicamente (usando malloc e calloc) --------> stack
Estou me referindo a essas variáveis apenas da perspectiva C.
Corrija-me se estiver errado, pois sou novo em C.
c
memory
memory-management
types
starkk92
fonte
fonte
main
é apenas outra função. Variáveis vão para a pilha, a menos que sejamalloc
como em qualquer outro lugar.Respostas:
Você acertou algumas delas, mas quem escreveu as perguntas o enganou em pelo menos uma pergunta:
main
função ----->heaptambém empilham (o professor estava tentando enganá-lo)char *arr
,int *arr
) ------->pilhadados ou pilha, dependendo do contexto. C permite declarar umstatic
ponteiro global ou um ponteiro; nesse caso, o ponteiro em si acabaria no segmento de dados.malloc
,calloc
,realloc
) -------->pilhapilhaVale ressaltar que a "pilha" é oficialmente chamada de "classe de armazenamento automático".
fonte
alloca
que funciona de maneira semelhantemalloc
, mas faz a alocação de pilha.Para os futuros visitantes que possam estar interessados em conhecer esses segmentos de memória, estou escrevendo pontos importantes sobre 5 segmentos de memória em C:
Alguns heads-up:
5 segmentos de memória em C:
1. Segmento de código
printf("Hello, world")
sequência "Olá, mundo" é criada no segmento de código / texto. Você pode verificar isso usando osize
comando no Linux OS.Segmento de dados
O segmento de dados é dividido nas duas partes abaixo e geralmente fica abaixo da área de pilha ou em algumas implementações acima da pilha, mas o segmento de dados nunca fica entre a área de pilha e pilha.
2. Segmento de dados não inicializado
int globalVar;
ou variável local estáticastatic int localStatic;
será armazenada no segmento de dados não inicializado.0
ouNULL
ainda assim, ela será direcionada para o segmento de dados não inicializado ou bss.3. Segmento de dados inicializado
int globalVar = 1;
ou variável local estáticastatic int localStatic = 1;
será armazenada no segmento de dados inicializado.4. Segmento de pilha
5. Segmento de Heap
malloc
,calloc
ourealloc
métodos.int* prt = malloc(sizeof(int) * 2)
então oito bytes serão alocados no heap e o endereço de memória desse local será retornado e armazenado naptr
variável optr
variável estará na pilha ou no segmento de dados, dependendo da maneira como é declarada / usada.fonte
Corrigiu suas frases erradas
variáveis constantes locais -----> stack
variável constante global inicializada -----> segmento de dados
variável constante global não inicializada -----> bss
variáveis declaradas e definidas na função principal -----> stack
ponteiros (ex: char * arr, int * arr) -------> o tamanho dessa variável de ponteiro estará na pilha.
Considere que você está alocando memória de n bytes (usando
malloc
oucalloc
) dinamicamente e, em seguida, tornando o ponteiro variável para apontá-lo. Agora que osn
bytes de memória estão no heap e a variável do ponteiro solicita 4 bytes (se a máquina de 64 bits tiver 8 bytes), que estarão na pilha para armazenar o ponteiro inicial dosn
bytes do bloco de memória.Nota: As variáveis de ponteiro podem apontar a memória de qualquer segmento.
espaço alocado dinamicamente (usando malloc, calloc) --------> heap
fonte
Uma arquitetura de desktop popular divide a memória virtual de um processo em vários segmentos :
Segmento de texto: contém o código executável. O ponteiro de instruções aceita valores nesse intervalo.
Segmento de dados: contém variáveis globais (ou seja, objetos com ligação estática). Subdividido em dados somente leitura (como constantes de seqüência de caracteres) e dados não inicializados ("BSS").
Segmento de pilha: contém a memória dinâmica do programa, ou seja, o armazenamento gratuito ("heap") e os quadros de pilha locais para todos os threads. Tradicionalmente, a pilha C e a pilha C costumavam crescer no segmento de pilhas de extremidades opostas, mas acredito que a prática foi abandonada porque é muito insegura.
O programa CA normalmente coloca objetos com duração de armazenamento estático no segmento de dados, objetos alocados dinamicamente no armazenamento gratuito e objetos automáticos na pilha de chamadas do encadeamento em que ele vive.
Em outras plataformas, como o antigo modo real x86 ou em dispositivos incorporados, as coisas podem obviamente ser radicalmente diferentes.
fonte
Do ponto de vista da linguagem C , tudo o que importa é extensão, escopo, vínculo e acesso; exatamente como os itens são mapeados para diferentes segmentos de memória depende da implementação individual e isso varia. O padrão de linguagem não fala sobre segmentos de memória em tudo . A maioria das arquiteturas modernas atua da mesma maneira; variáveis de escopo de bloco e argumentos de função serão alocados da pilha, variáveis de escopo de arquivo e estáticas serão alocadas de um segmento de dados ou código, memória dinâmica será alocada de uma pilha, alguns dados constantes serão armazenados em segmentos somente leitura , etc.
fonte
Uma coisa que é preciso ter em mente sobre o armazenamento é a regra como se . O compilador não precisa colocar uma variável em um local específico - em vez disso, pode colocá-la onde quiser, desde que o programa compilado se comporte como se fosse executado na máquina C abstrata, de acordo com as regras da máquina C abstrata. Isso se aplica a todas as durações de armazenamento . Por exemplo:
42
o código de montagem gerado, mas nenhum sinal de404
.const
ou efetivamenteconst
não precisa estar na memória. Exemplo - o compilador pode provar quefoo
é eficazconst
e enfatiza seu uso no código.bar
possui ligação externa e o compilador não pode provar que não seria alterado fora do módulo atual, portanto, não está embutido.malloc
não precisa residir na memória alocada do heap! Exemplo - observe como o código não tem uma chamadamalloc
e nem o valor 42 é armazenado na memória, ele é mantido em um registro!malloc
e a referência é perdida sem desalocar o objeto semfree
precisar vazar memória ...malloc
não precisa estar dentro do heap abaixo da quebra do programa (sbrk(0)
) no Unixen ...fonte
Não, eles podem estar na pilha ou no segmento de dados. Eles podem apontar para qualquer lugar.
fonte
main
e variáveis dinamicamente alocados são errado tambémfonte
Exemplos mínimos executáveis do Linux com análise de desmontagem
Como esse é um detalhe da implementação não especificado pelos padrões, vamos apenas dar uma olhada no que o compilador está fazendo em uma implementação específica.
Nesta resposta, irei vincular a respostas específicas que fazem a análise ou fornecê-la diretamente aqui e resumir todos os resultados aqui.
Todos eles estão em várias versões do Ubuntu / GCC, e os resultados provavelmente são bastante estáveis entre as versões, mas se encontrarmos alguma variação, vamos especificar versões mais precisas.
Variável local dentro de uma função
Seja ele
main
ou qualquer outra função:Como mostrado em: O que <valor otimizado> significa em gdb?
-O0
: pilha-O3
: registra se não derramar, empilhar de outra formaPara obter motivação sobre o motivo da pilha existir, consulte: Qual é a função das instruções push / pop usadas nos registradores na montagem x86?
Variáveis globais e
static
variáveis de função0
ou não inicializado (e, portanto, implicitamente inicializado para0
):.bss
seção, consulte também: Por que o segmento .bss é necessário?.data
seçãochar *
echar c[]
Como mostrado em: Onde as variáveis estáticas são armazenadas em C e C ++?
TODO literais de string muito grandes também serão colocados na pilha? Ou
.data
? Ou a compilação falha?Argumentos de função
Deve passar pela convenção de chamada relevante, por exemplo: https://en.wikipedia.org/wiki/X86_calling_conventions para X86, que especifica registros específicos ou locais de pilha para cada variável.
Então, como mostrado em O que <valor otimizado> significa em gdb? ,
-O0
coloca tudo na pilha, enquanto-O3
tenta usar os registros o máximo possível.Se a função for incorporada, no entanto, elas serão tratadas como locais comuns.
const
Acredito que isso não faz diferença, porque você pode descartá-lo.
Por outro lado, se o compilador é capaz de determinar que alguns dados nunca são gravados, ele poderia, em teoria, colocá-lo
.rodata
mesmo que não seja const.Análise TODO.
Ponteiros
Eles são variáveis (que contêm endereços, que são números), iguais aos demais :-)
malloc
A questão não faz muito sentido
malloc
, poismalloc
é uma função e em:*i
é uma variável que contém um endereço e, portanto, se enquadra no caso acima.Quanto ao funcionamento do malloc internamente, quando você o chama, o kernel do Linux marca determinados endereços como graváveis em suas estruturas de dados internas e, quando são tocados pelo programa inicialmente, ocorre uma falha e o kernel ativa as tabelas de páginas, o que permite o acesso. acontece sem segfaul: Como funciona a paginação x86?
Observe, no entanto, que isso é basicamente exatamente o que o
exec
syscall faz quando você tenta executar um executável: ele marca as páginas nas quais deseja carregar e grava o programa, veja também: Como o kernel obtém um arquivo binário executável em execução linux? Exceto queexec
tem algumas limitações extras sobre onde carregar (por exemplo, se o código não é realocável ).O syscall exato usado
malloc
émmap
nas implementações modernas de 2020 e no passadobrk
foi usado: malloc () usa brk () ou mmap ()?Bibliotecas dinâmicas
Basicamente, é
mmap
editado na memória: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710variáveis ambientais e
main
'sargv
Acima da pilha inicial: /unix/75939/where-is-the-environment-string-actual-stored TODO por que não em .data?
fonte