Por que C permite várias declarações globais da mesma variável, mas NÃO várias declarações locais?

8

Percebi que se eu declarar uma variável global várias vezes, o compilador nem emitirá um aviso.

No entanto, se eu declarar uma variável local em uma função várias vezes, por exemplo, o compilador gcc gera um erro e não compila o arquivo. (Eu pergunto em termos de gcc, mas essa é mais uma questão geral de design de linguagem, não uma questão sobre gcc, porque acho que provavelmente outros compiladores se comportam de maneira semelhante).

Qual a explicação para esse comportamento?

yoyo_fun
fonte
Só para ter certeza, sua variável global sempre teve o mesmo tipo, certo?
Walfrat 04/10
@ Walfrat Sim, a variável é sempre declarada do mesmo tipo. Se duas variáveis ​​com o mesmo nome, mas com tipo diferente, forem declaradas globalmente, o gcc emitirá o erro "tipos conflitantes para uma (variável)"
yoyo_fun 4/17/17
3
Você não pode declarar uma variável local nem uma vez. Tudo o que você pode fazer é defini-lo. Declarar uma variável é dizer ao compilador o que é. Definir uma variável é dizer ao compilador para alocar memória para ela. Você deve definir todas as variáveis. Em C, a definição de uma variável global pode ser usada para uma declaração várias vezes. Mas se o programa tiver apenas extern int x;, que é uma declaração, a compilação será interrompida, pois não há lugar onde a memória seja alocada para a variável.
shawnhcorey

Respostas:

11

De acordo com as diretrizes de codificação :

No conjunto de unidades de tradução e bibliotecas que constituem um programa inteiro, cada declaração de um identificador específico com ligação externa indica o mesmo objeto ou função. Dentro de uma unidade de conversão, cada declaração de um identificador com ligação interna indica o mesmo objeto ou função. Cada declaração de um identificador sem ligação indica uma entidade única.

A variável local não tem ligação. então existe um nome Colisão ocorre. Portanto, várias declarações da variável local não são possíveis.

A variável global possui ligação externa. Portanto, várias declarações de variáveis ​​globais são possíveis.

msc
fonte
7
Essa resposta é boa, no entanto, a pergunta óbvia de acompanhamento é: qual é a lógica por trás dessa definição?
Doc Brown
Com muitas peculiaridades em C, a lógica é "compiladores pré-padrão em C apenas fizeram dessa maneira". Se você observar a complexidade da "definição provisória", é bem provável que este seja o caso aqui.
Sebastian Redl
9

O @msc fornece uma boa introdução às regras por trás desse comportamento.

Percebi que se eu declarar uma variável global várias vezes, o compilador nem emitirá um aviso.

C tem três tipos de declarações globais para objetos, a saber, aquelas que são (e eu estou comentando staticaqui):

  1. declarações que não são definições - extern int a;
  2. declarações que também são definições - int a = 3;ouextern int a = 3;
  3. definições provisórias - int a;

Múltiplas declarações do tipo 1 e 3 são permitidas, enquanto no máximo uma definição (do tipo 2) é permitida.


Qual a explicação para esse comportamento?

Se você também está perguntando sobre a motivação dessas regras, é o suporte para compilação separada . (Ver unidade de tradução ).

Para dividir um programa em vários arquivos compilados separadamente, precisamos de alguns recursos, a saber: (a) poder declarar sem necessariamente definir e (b) declaração direta .

Dentro de uma unidade de tradução, precisamos nos referir a funções e dados globais em outra unidade de tradução. E também gostaríamos de uma verificação de erro, aqui, para descobrir definições ausentes e definições duplicadas erradas.

Às vezes, na mesma unidade de tradução, declaramos um global e o definimos mais tarde. Isso pode acontecer se precisarmos de uma declaração direta por algum motivo, ou se usarmos um arquivo de cabeçalho comum (que fornece declarações) dentro de uma unidade de tradução que também oferece definições explícitas.

Como a compilação separada em C se aplica ao vincular funções e dados globais, esses recursos são necessários no nível global, mas não no nível local.

Como o @msc aponta, nada disso é necessário para variáveis ​​locais, pois elas não têm ligação.

C (como muitos outros idiomas) não fornece ligação para variáveis ​​locais, pois o idioma não tenta suportar uma única função que abrange várias unidades de tradução separadas.

(Obviamente, você pode ter uma função em vários arquivos de origem, mas não em várias unidades de tradução.)

Uma definição provisória funciona como uma declaração, pois é permitida em várias unidades de tradução (e também combina bem com outras declarações). No entanto, se não houver uma definição (não tentativa) para o identificador em todo o programa, o conjunto de (uma ou mais) definições tentativas em várias unidades de conversão (para um identificador) será usado como uma definição para o objeto cujo inicializador é zero.

Isso pode ser implementado colocando-os na seção .BSS com o tamanho e o alinhamento adequados; o vinculador os corresponderá à definição verdadeira, se encontrado, ou corresponderá um ao outro, dando a eles espaço zerado no BSS.


A noção de compilação separada pode ser totalmente suportada sem o recurso de definições provisórias - acho que as definições provisórias existem principalmente por razões históricas. (Não estou dizendo que eles não são úteis, apenas se o idioma foi criado hoje, isso pode ser visto como desnecessário e, portanto, não ser oferecido.)

Erik Eidt
fonte