Classes de armazenamento
Nesta aula, exploramos as classes de armazenamento em C: auto, register, static e extern. Aprendemos como elas controlam o tempo de vida, visibilidade e localização de variáveis, com exemplos práticos e exercícios para fixar o conteúdo.
As classes de armazenamento em C definem o escopo, o tempo de vida e, em alguns casos, o local de armazenamento de variáveis e funções. Elas são fundamentais para o controle fino de como os dados são mantidos na memória e como diferentes partes do programa podem acessá-los. Nesta aula, vamos explorar as quatro classes principais: auto, register, static e extern, entendendo suas diferenças e aplicações práticas.
Dominar essas classes é essencial para escrever código eficiente e evitar bugs sutis relacionados a variáveis globais, locais e à comunicação entre arquivos. Vamos começar com as classes mais simples e avançar para as mais complexas, sempre com exemplos claros.
auto, register
A classe auto é a padrão para variáveis locais. Ela indica que a variável é automática, ou seja, é criada na entrada do bloco em que é declarada e destruída na saída. Na prática, raramente escrevemos auto porque é o comportamento implícito de qualquer variável local não estática.
Já a classe register sugere ao compilador que a variável seja armazenada em um registrador do processador, para acesso mais rápido. No entanto, o compilador pode ignorar essa sugestão, e não é possível obter o endereço de uma variável register (com o operador &). O uso de register é raro hoje em dia, pois os compiladores otimizam bem o código automaticamente.
#include <stdio.h>
int main() {
// auto é implícito, podemos omitir
auto int x = 10; // equivalente a int x = 10;
// register: sugestão para armazenar em registrador
register int y = 20;
printf("x = %d, y = %d\n", x, y);
// Não é permitido: register int *p = &y; // erro!
return 0;
}No exemplo, x é automaticamente auto e y é register. A tentativa de obter o endereço de y resultaria em erro de compilação.
static
A classe static tem dois usos principais: em variáveis locais e em variáveis/ funções globais. Quando aplicada a uma variável local, ela altera o tempo de vida: a variável não é destruída ao sair do bloco, mas mantém seu valor entre chamadas da função. O escopo continua sendo o bloco, mas a variável é inicializada apenas uma vez.
Quando aplicada a uma variável global ou função, static restringe a visibilidade ao arquivo onde é declarada, impedindo que outros arquivos a acessem via extern. Isso é útil para encapsulamento.
#include <stdio.h>
void contador() {
static int count = 0; // inicializada apenas uma vez
count++;
printf("chamada %d\n", count);
}
static int interno = 100; // visível apenas neste arquivo
int main() {
contador(); // chamada 1
contador(); // chamada 2
contador(); // chamada 3
printf("interno = %d\n", interno);
return 0;
}No código, a variável count mantém seu valor entre chamadas, porque é static. Sem static, ela seria reinicializada a cada chamada.
extern
A classe extern é usada para declarar uma variável ou função que é definida em outro arquivo ou em outro ponto do código. Ela não aloca memória; apenas informa ao compilador que a variável existe em algum lugar. Isso permite que múltiplos arquivos compartilhem variáveis globais.
É importante diferenciar declaração (com extern) de definição (sem extern). A definição aloca memória e pode ser feita apenas uma vez em todo o programa.
// arquivo1.c
#include <stdio.h>
int global = 42; // definição
void funcao();
int main() {
printf("global em main: %d\n", global);
funcao();
return 0;
}
// arquivo2.c
extern int global; // declaração, não definição
void funcao() {
printf("global em funcao: %d\n", global);
}Neste exemplo, a variável global é definida em arquivo1.c e usada em arquivo2.c via extern. Se tentássemos definir global novamente em arquivo2.c, haveria erro de linkagem.
Tempo de vida e visibilidade
O tempo de vida de uma variável é o período durante o qual ela existe na memória. Variáveis auto e register têm tempo de vida automático (do início ao fim do bloco). Variáveis static locais têm tempo de vida estático (duram todo o programa, mas só são acessíveis no bloco). Variáveis globais (incluindo extern) também têm tempo de vida estático.
A visibilidade (ou escopo) determina onde a variável pode ser referenciada. Variáveis locais são visíveis apenas no bloco onde foram declaradas. Variáveis globais são visíveis em todo o arquivo a partir do ponto de declaração, e em outros arquivos se declaradas com extern. static global restringe a visibilidade ao arquivo.
Resumindo em uma tabela:
| Classe | Escopo | Tempo de vida | Localização |
|---|---|---|---|
| auto | Bloco | Automático | Memória (pilha) |
| register | Bloco | Automático | Registrador (sugestão) |
| static (local) | Bloco | Estático | Memória (área estática) |
| static (global) | Arquivo | Estático | Memória (área estática) |
| extern | Arquivo (ou outros) | Estático | Memória (definido em outro lugar) |
Boas práticas
- Evite variáveis globais sempre que possível; prefira passar parâmetros.
- Use
staticpara funções que não precisam ser visíveis fora do arquivo. - Use
externapenas para compartilhar variáveis entre arquivos, e sempre com moderação. - Não use
registerem código moderno; os compiladores otimizam melhor. - Inicialize sempre variáveis estáticas para evitar valores indefinidos.
Exercícios
- Explique a diferença entre tempo de vida automático e estático, dando um exemplo de cada.
- Escreva um programa que use uma variável
staticlocal para contar quantas vezes uma função foi chamada. - O que acontece se você tentar obter o endereço de uma variável declarada como
register? Justifique. - Considere dois arquivos:
a.cdefineint x = 5;eb.cdeclaraextern int x;. Seb.ctentar modificarx, qual será o efeito? Explique. - Escreva um programa que demonstre o uso de
staticem uma variável global para limitar o acesso a outro arquivo.
#include <stdio.h>
void func() {
static int count = 0;
count++;
printf("Chamada %d\n", count);
}
int main() {
func();
func();
func();
return 0;
}register não têm endereço de memória (podem estar em registradores). O padrão C proíbe o uso do operador & em tais variáveis.x é a mesma (compartilhada). Modificá-la em b.c altera o valor para ambos os arquivos, pois extern não cria uma nova variável, apenas referencia a existente.// arquivo1.c
static int segredo = 42;
int main() {
printf("%d\n", segredo);
return 0;
}
// arquivo2.c (não pode acessar segredo, pois é static)
// extern int segredo; // erro de linkagem, porque segredo não é visível fora de arquivo1.c