Estes modificadores de tipo atuam sobre a maneira com a qual o compilador vai armazenar a variável.
O especificador de classe de armazenamento auto define variáveis automáticas, isto é, variáveis locais. Raramente usado pois todas as variáveis locais do C são auto por definição.
O extern define variáveis que serão usadas em um arquivo apesar de terem sido declaradas em outro. Ao contrário dos programas até aqui vistos, podemos ter programas de vários milhares de linhas. Estes podem ser divididos em vários arquivos (módulos) que serão compilados separadamente. Digamos que para um programa grande tenhamos duas variáveis globais: um inteiro count e um float sum. Estas variáveis são declaradas normalmente em um dos módulos do programa. Por exemplo:
int count; float sum; main (void) { ... return 0; }
Num outro módulo do programa temos uma rotina que deve usar as variáveis globais acima. Digamos que a rotina que queremos se chama RetornaCount() e retorna o valor atual de count. O problema é que este módulo será compilado em separado e não tomará conhecimento dos outros módulos. O que fazer? Será que funcionaria se fizermos assim:
int count; /* errado */ float sum; int RetornaCount (void) { return count; }
Não. O módulo compilaria sem problema, mas, na hora que fizermos a linkagem (união dos módulos já compilados para gerar o executável) vamos nos deparar com uma mensagem de erro dizendo que as variáveis globais count e sum foram declaradas mais de uma vez. A maneira correta de se escrever o módulo com a função RetornaCount() é:
extern int count; /* certo */ extern float sum; int RetornaCount (void) { return count; }
Assim, o compilador irá saber que count e sum estão sendo usados no bloco mas que foram declarados em outro.
O funcionamento das variáveis declaradas como static depende se estas são globais ou locais.
Variáveis globais static funcionam como variáveis globais dentro de um módulo, ou seja, são variáveis globais que não são (e nem podem ser) conhecidas em outros modulos. Isto é util se quisermos isolar pedaços de um programa para evitar mudanças acidentais em variáveis globais.
Variáveis locais static são variáveis cujo valor é mantido de uma chamada da função para a outra. Veja o exemplo:
int count (void) { static int num=0; num++; return num; }
A função count() retorna o número de vezes que ela já foi chamada. Veja que a variável local int é inicializada. Esta inicialização só vale para a primeira vez que a função é chamada pois num deve manter o seu valor de uma chamada para a outra. O que a função faz é incrementar num a cada chamada e retornar o seu valor. A melhor maneira de se entender esta variável local static é implementando. Veja por si mesmo, executando seu próprio programa que use este conceito.
O computador tem a memória principal e os registradores da CPU. As variáveis (assim como o programa como um todo) são armazenados na memória. O modificador register diz ao compilador que a variável em questão deve ser, se possível, usada em um registrador da CPU.
Vamos agora ressaltar vários pontos importantes. Em primeiro lugar, porque usar o register? Variáveis nos registradores da CPU vão ser acessadas em um tempo muito menor pois os registradores são muito mais rápidos que a memória. Em segundo lugar, em que tipo de variável usar o register? O register não pode ser usado em variáveis globais. Isto implicaria que um registrador da CPU ficaria o tempo todo ocupado por conta de uma variável. Os tipos de dados onde é mais aconselhado o uso do register são os tipos char e int, mas pode-se usá-lo em qualquer tipo de dado. Em terceiro lugar, o register é um pedido que o programador faz ao compilador. Este não precisa ser atendido necessariamente.
Um exemplo do uso do register é dado:
main (void) { register int count; for (count=0;count<10;count++) { ... } return 0; }
O loop for acima será executado mais rapidamente do que seria se não usássemos o register. Este é o uso mais recomendável para o register: uma variável que será usada muitas vezes em seguida.
Auto-Avaliação
Veja como você está:
Considerando o conceito e finalidade dos modificadores de tipo,
relacione as afirmativas com as palavras reservadas correspondentes (todas as afirmativas
devem ser preenchidas com o número relacionado ao modificador correspondente, e existe
pelo menos uma afirmativa para cada modificador):
(1)const
(3)extern (5)register (7)void
(2)volatile
(4)static
(6)auto
( ) informa ao compilador que o valor da variável não
pode ser alterado por nenhum comando do programa, mas que pode ser inicializado
( ) informa ao compilador que nenhum valor será devolvido pela função
( ) informa ao compilador que a variável pode ser modificada por algum evento
que não está sob o controle do programa
( ) avisa ao compilador que as variáveis que o seguem já foram declaradas em
outro lugar
( ) torna a variável permanente, mantendo seu valor entre chamadas
( ) útil ao escrever funções generalizadas e funções de biblioteca que
podem ser usadas por outros programadores, pois permite esconder porções do
programa de outras partes do código, evitando assim o uso de variável global
( ) quando apontadores forem passados para a função, garante que nenhum
código na função poderá modificar os objetos apontados
( ) armazena o valor da variável em um registrador da CPU, acelerando
operações
( ) usada para declarar variáveis locais automáticas, mas muito pouco usada
por já ser o padrão (default)
( ) avisa ao compilador que a variável em questão sera largamente usada e
deve permanecer acessível da forma mais eficiente possível
( ) permite ao compilador conhecer a variável sem criar armazenamento para
ela novamente em outro modulo
Curso de C do CPDEE/UFMG - 1996 - 1999