A palavra-chave 'estático' em C tem dois significados fundamentalmente diferentes.
Limite de escopo
Nesse contexto, 'estático' se emparelha com 'externo' para controlar o escopo de um nome de variável ou função. Static faz com que o nome da variável ou função esteja disponível apenas em uma única unidade de compilação e disponível apenas para o código que existe após a declaração / definição no texto da unidade de compilação.
Essa limitação em si realmente significa apenas algo se e somente se você tiver mais de uma unidade de compilação em seu projeto. Se você tiver apenas uma unidade de compilação, ela ainda funciona, mas esses efeitos são inúteis (a menos que você goste de pesquisar nos arquivos de objetos para ler o que o compilador gerou)
Como observado, essa palavra-chave nesse contexto é emparelhada com a palavra-chave 'extern', que faz o oposto - tornando o nome da variável ou função vinculável ao mesmo nome encontrado em outras unidades de compilação. Portanto, você pode considerar 'estático' exigindo que a variável ou o nome seja encontrado na unidade atual de compilação, enquanto 'externo' permite a ligação da unidade de compilação cruzada.
Vida estática
Vida útil estática significa que a variável existe durante toda a duração do programa (por mais tempo que seja.) Quando você usa 'static' para declarar / definir uma variável em uma função, significa que a variável é criada algum tempo antes de seu primeiro uso ( o que significa que, toda vez que a experimento, a variável é criada antes do início do main () e não é destruída posteriormente. Nem mesmo quando a execução da função é concluída e ela retorna ao seu chamador. E, assim como as variáveis de vida estática declaradas fora das funções, elas são inicializadas no mesmo momento - antes do início do main () - para um zero semântico (se nenhuma inicialização for fornecida) ou para um valor explícito especificado, se fornecido.
Isso é diferente das variáveis de função do tipo 'auto', que são criadas novas (ou como se fossem novas) cada vez que a função é inserida e depois são destruídas (ou como se fossem destruídas) quando a função é encerrada.
Ao contrário do impacto de aplicar 'estático' em uma definição de variável fora de uma função, o que afeta diretamente seu escopo, declarar uma variável de função (dentro de um corpo de função, obviamente) como 'estático' não afeta seu escopo. O escopo é determinado pelo fato de ter sido definido dentro de um corpo de função. As variáveis estáticas do tempo de vida definidas nas funções têm o mesmo escopo que outras variáveis 'auto' definidas nos corpos das funções - escopo das funções.
Sumário
Portanto, a palavra-chave 'estática' possui contextos diferentes, com o que significa "significados muito diferentes". O motivo pelo qual foi usado de duas maneiras, assim, foi evitar o uso de outra palavra-chave. (Houve uma longa discussão sobre isso.) Considerou-se que os programadores podiam tolerar o uso e o valor de evitar mais uma palavra-chave na linguagem, sendo mais importante (do que argumentos de outra maneira.)
(Todas as variáveis declaradas fora das funções têm vida útil estática e não precisam da palavra-chave 'static' para torná-la verdadeira. Portanto, esse tipo de liberação da palavra-chave a ser usada ali significa algo completamente diferente: 'visível apenas em uma única compilação unidade. 'É um tipo de hack.)
Nota específica
char não assinado volátil estático PORTB @ 0x06;
A palavra 'estático' aqui deve ser interpretada como significando que o vinculador não tentará corresponder várias ocorrências de PORTB que podem ser encontradas em mais de uma unidade de compilação (assumindo que seu código tenha mais de uma).
Ele usa uma sintaxe especial (não portátil) para especificar o "local" (ou o valor numérico do rótulo, que geralmente é um endereço) do PORTB. Portanto, o vinculador recebe o endereço e não precisa encontrar um para ele. Se você tivesse duas unidades de compilação usando essa linha, cada uma delas acabaria apontando para o mesmo local. Portanto, não há necessidade de rotulá-lo de 'externo', aqui.
Se eles usassem 'extern', isso poderia representar um problema. O vinculador seria capaz de ver (e tentaria corresponder) várias referências ao PORTB encontradas em várias compilações. Se todos eles especificarem um endereço como este, e os endereços NÃO forem os mesmos por algum motivo [erro?], O que ele deve fazer? Reclamar? Ou? (Tecnicamente, com 'extern' a regra geral seria que apenas UMA unidade de compilação especificaria o valor e as outras não.)
É mais fácil rotulá-lo como 'estático', evitando que o vinculador se preocupe com conflitos e simplesmente culpe os erros por endereços incompatíveis com quem alterou o endereço para algo que não deveria ser.
De qualquer maneira, a variável é tratada como tendo uma 'vida útil estática'. (E 'volátil'.)
Uma declaração não é uma definição , mas todas as definições são declarações
Em C, uma definição cria um objeto. Também o declara. Porém, uma declaração geralmente não (veja a nota abaixo) cria um objeto.
A seguir estão definições e declarações:
static int a;
static int a = 7;
extern int b = 5;
extern int f() { return 10; }
A seguir, não são definições, mas são apenas declarações:
extern int b;
extern int f();
Observe que as declarações não criam um objeto real. Eles apenas declaram os detalhes, que o compilador pode usar para ajudar a gerar o código correto e fornecer mensagens de aviso e erro, conforme apropriado.
Acima, eu digo "normalmente", aconselhando. Em alguns casos, uma declaração pode criar um objeto e, portanto, é promovida a uma definição pelo vinculador (nunca pelo compilador.) Portanto, mesmo nesse caso raro, o compilador C ainda pensa que a declaração é apenas uma declaração. É a fase do vinculador que faz as promoções necessárias de alguma declaração. Tenha isso em mente.
Nos exemplos acima, se houver apenas declarações para um "extern int b;" em todas as unidades de compilação vinculadas, o vinculador é responsável pela criação de uma definição. Esteja ciente de que este é um evento de tempo do link. O compilador é completamente inconsciente durante a compilação. Só pode ser determinado no momento do link, se uma declaração desse tipo for mais promovida.
O compilador está ciente de que "static int a;" não pode ser promovido pelo vinculador no momento do link, portanto, essa é realmente uma definição no momento da compilação .