Ir para o conteúdo
kodiak

Tipos de armazenamento

Mensagens Recomendadas

kodiak

Viva pessoal.

Estou a aprender C e estou com algumas dúvidas.

Preciso de saber o que é armazenamento estático, pilha e heap. Devo estar a procurar mal porque não estou a dar com isto.

Alguma sugestão onde posso ir buscar a explicação?

obrigado,

kodiak

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

este artigo na Wikipedia (ou em português).

Basicamente esses nomes referem-se a maneiras diferentes de organizar e aceder a informações.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
kodiak

este artigo na Wikipedia (ou em português).

Basicamente esses nomes referem-se a maneiras diferentes de organizar e aceder a informações.

Olá pmg.

Confesso que fiquei um bocado confuso com os artigos que sugeriste mas acho que deram base para ir à procura de outros.

Vamos ver se entendi.

Imaginemos o seguinte código (apenas para me tentar explicar):


int a = 10;

int soma (int numero){
     return a + numero;
}

void main(){
/*Várias coisas aqui dentro*/

}

Pelo que entendi, o int a é armazenamento estático visto ser "global" a todo o programa;

O main() e a função soma são pilha. Sempre que a soma e chamada, coloca o resultado na pilha (stack) mas assim que é finalizada a função, a memória é libertada.

O armazenamento dinâmico (heap) é quando se fazem os mallocs. O espaço fica armazenado na memória fica "reservado" até que seja libertado. Como ainda não vi esta parte não percebo muito bem.

É mais ou menos isto?

obrigado,

kodiak

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Em C há duas caracteristicas que tens de ter em atenção: "lifetime" (tempo de vida) e "scope" (alcance? ???).

O 'alcance' dum objecto, basicamente, é definido aquando da declaração do objecto.

O 'tempo de vida' dum objecto, basicamente, é definido aquando da definição do objecto.

Os 'tempos de vida' existentes são: estático, automático, e dinâmico.

Um objecto com um tempo de vida estático existe (e guarda o seu valor) desde antes do início da função main até ao fim da execução do programa.

Um objecto com tempo de vida automático é "criado e destruído automaticamente pelo compilador".

Um objecto com tempo de vida dinâmico é criado e destruído "manualmente pelo programador".

Uma maneira prática de gerir estes 3 diferemtes tipos de objectos é agrupá-los cada um na sua zona. Nota que este agrupamento não é necessário.

Com este agrupamento, costuma dar-se o nome de "BSS", "DATA", "armazenamento estático", ... à zona onde se guardam os objectos com static lifetime; ou "heap" à zona onde se guardam objectos com dynamic lifetime; ou "stack" à zona onde se guardam objectos com automatic lifetime.

Basicamente ... não precisas de saber os nomes dessas zonas (nem o seu funcionamento) para fazeres programas que funcionem :)


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara

Talvez seja útil explicar o que é a pilha: é uma zona de memória que é indicada ao CPU como podendo ser usada para guardar conteúdos de registos do mesmo. Assim quando é usada uma instrução de chamada de subrotina (CALL) ou de armazenamento dum registo (PUSH) os valores a guardar são metidos nessa pilha, avançando o topo da mesma para a próxima posição (atenção que quero mesmo dizer posição). Quando esses valores são retirados da pilha, com uma instrução de retorno (RET) ou de recuperação dum registo (POP) o topo da pilha passa para a posição anterior. Aqui falo em posições pois nos CPU x86 a pilha cresce para endereços inferiores de memória. Um primeiro PUSH EAX grava no endereço 0x00010000 (p.e.) mas o próximo vaí gravar no endereço 0x0000FFFC.

Existindo esta funcionalidade do CPU, muitas linguagens de programação, quando compiladas para CPU x86, usam a pilha para passar parâmetros a subrotinas e para armazenamento de variáveis locais às mesmas. Para isso usam-se as chamadas 'stack frame's, em que o compilador cria código-máquina para guardar o endereço actual do topo da pilha (que vai descendo na memória) e usa esse endereço como base para aceder aos parâmetros passados e potencialmente a variáveis que sejam alocadas dentro da subrotina. Quando é feita a entrada na subrotina é criada a 'stack frame', que é destruída na saída da mesma.

Como a 'stack frame' é destruída à saída da subrotina, qualquer variável local à mesma terá um conteúdo indefinido após a saída da subrotina. Isso implica que NUNCA se pode passar ponteiros para variáveis locais para fora da subrotina onde são declaradas.Por exemplo, isto :

#include <string.h>

char * teste(void)
{
  char string[10];

  strcpy(string,"teste");
  return string;
}

int main()
{
  char * ptr;

  ptr = teste();
  return 0;
}

quando compilado pelo GCC dá o aviso 'warning: function returns address of local variable'.

Outra perigo da utilização da pilha para armazenar variáveis locais é que a pilha, como disse acima, também é usada para guardar os endereços de retorno das subrotinas. E como a pilha cresce para endereços inferiores, é muito fácil alterar o endereço de retorno duma subroutina, simplesmente escrevendo mais dados dentro duma variável do que o espaço alocado à mesma. Este código :

#include <string.h>

char * teste(void)
{
  char string[10];

  strcpy(string,"teste teste teste teste teste");
  return 0;
}

int main()
{
  char * ptr;

  ptr = teste();
  return 0;
}

apesar de compilar sem erros nenhuns, garante um estouro pois a instrução 'strcpy' vai escrever por cima do endereço de retorno da função (assim chamada em C) 'teste'. É assim que começam os ataques virais, tendo o cuidado de o valor a substituir o endereço de retorno da subrotina atacada fazer sentido, garantindo assim a execução de código que doutra maneira seria invisível para o CPU.

Tendo estes riscos, porque se usa a pilha para guardar variáveis ? Porque enquanto a alocação de variáveis no 'heap' obriga a um grande conjunto de operações, que demoram tipicamente várias milhares de ciclos de CPU, a alocação de variáveis na pilha obriga apenas a decrementar o ponteiro para o topo da pilha (lembrar que a pilha normalmente desce na memória), o que é feito num ciclo apenas.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Desculpa lá bsccara, mas vou colocar aqui um parêntesis, pois parece-me que a definição não é a mais correcta.

Heap e Pilha(Stack) são tipos de estruturas de dados, tal como listas ligadas e arvores binárias.

Acontece que os SO's usam estruturas deste tipo para implementarem algumas das suas funcionalidades.

As pessoas referem-se as essas zonas de memória (como tu descreves) pelo nome do tipo de estrutura implementada. Por exemplo, a stack que te referes é uma estrutura utilizada para guardar os dados dos processos em execução.

O mesmo para a heap, que é também o nome que se dá à zona de memória livre, que normalmente é usada para alocar memória dinâmica. Basicamente porque a estrutura com que são controlados os endereços de memória livres é uma estrutura do tipo Heap.

Espero ter aclarado mais um pouco este assunto, já que os nomes podem ser ambíguos. Quanto ao armazenamento estático, acho que o esclarecimento do pmg está muito bom, nada a acrescentar.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara

Heap e Pilha(Stack) são tipos de estruturas de dados, tal como listas ligadas e arvores binárias.

Sim e não. Existe efectivamente um tipo de estrutura de dados chamada 'pilha' ou 'stack' mas que pode ser implementada de múltiplas maneiras (listas ligadas, arrays, etc.). A pilha de que falo é a gerida pelo CPU, que é usada pelas implementações do C em arquiteturas x86. Essa é a pilha onde são guardadas as variáveis locais. Essa pilha não tem implementação em software, é uma funcionalidade do CPU.

'Heap', como dizes abaixo é o termo usado para designar a memória livre que é acessível ao programa. Ao contrário do que dizes, não é uma estrutura de dados. Pode ser implementada usando múltiplas estruturas de dados (normalmente duplas listas ligadas). O link que incluis na resposta é para uma estrutura em árvore e no próprio texto da página é indicado 'A heap data structure should not be confused with the heap which is a common name for dynamically allocated memory.'.

Por exemplo, a stack que te referes é uma estrutura utilizada para guardar os dados dos processos em execução.

Não, o 'stack' a que me refiro é uma funcionalidade do CPU, não é uma estrutura de dados. E como referi não serve para guardar dados de processos; serve para guardar estado do CPU (vê as instruções CALL, RET, PUSH, POP do assembly x86). Muitas implementações de linguagens de programação usam essa funcionalidade para os seus fins, como as que indicas.

Convém também não confundir 'stack' com 'stack frame'. As 'stack frame's são usadas, em implementações de várias linguagens, para guardar endereços de retorno e variáveis locais. O 'stack' é a funcionalidade do CPU usada para as criar.

Basicamente porque a estrutura com que são controlados os endereços de memória livres é uma estrutura do tipo Heap.

Errado, ver acima.

Apenas continuei com a discussão por é importante perceber que abaixo das linguagens de alto nível existe outra linguagem (assembly) e que no final o computador apenas percebe uma: código-máquina. Não acredito que alguém consiga ser um bom programador em C sem ter uma noção de como funciona a maquinaria por baixo.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

A pilha de que falo é a gerida pelo CPU

...

Não, o 'stack' a que me refiro é uma funcionalidade do CPU

...

não é uma funcionalidade do CPU ... é uma estrutura implementada pelo sistema operativo escrita habitualmente no kernel ....


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bsccara

não é uma funcionalidade do CPU ... é uma estrutura implementada pelo sistema operativo escrita habitualmente no kernel ....

Não, É uma funcionalidade do CPU. O sistema operativo apenas está envolvido em inicializar os registos SS e ESP, aquando do inicio ou recomeço de execução duma 'thread'; guardá-los aquando da suspensão da mesma; mudança para o 'stack' do kernel aquando de execução de código no mesmo; e resposta a 'stack fault's, em código não-kernel, para aumentar o tamanho do segmento apontado pelo SS (a 'stack fault acontece quando já não existe espaço nesse segmento para mais um PUSH; ESP < 4).

Ou seja, o SO apenas virtualiza o acesso ao 'stack' de modo a que cada 'thread' tenha o seu próprio e responde à necessidade de mais 'stack' para essas 'threads'.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

O conceito de stack é um conceito abstracto. Assim como o conceito de Lista ligada. Uma lista ligada não passa no fundo de uma struct com determinadas características, que tu manuseias de uma determinada forma de modo a obteres o comportamento que se define como o comportamento de uma lista ligada.

O conceito de Stack é igual. Não interessa como tu representas a stack, que estruturas usas para implementar o comportamento que desejas. Até podes usar hashmaps, ou arvores binarias, ou mesmo variáveis simples... embora não haja necessidade.

Quanto a quem pertence a stack, se ao processador se ao SO, para mim isso é uma área cinzenta... Se por um lado tens razão, já que o processador tem instruções de suporte a operações na stack (arquitectura x86 suporta, pode não ser válido para outras arquitecturas), por outro lado a stack é gerida pelo SO (é da responsabilidade do SO a gestão de memória), e é este que define o tamanho da stack para cada processo e, em última análise, qual é o valor que vai estar no registo stack pointer do CPU.

Mas seja de que fôr a "stack" apenas tem esse nome por é uma implementação de do conceito abstracto Stack.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.