Perché C consente più dichiarazioni globali della stessa variabile ma NON più dichiarazioni locali?

8

Ho notato che se dichiaro una variabile globale più volte il compilatore non emette nemmeno un avviso.

Tuttavia, se dichiaro una variabile locale in una funzione più volte, ad esempio, il compilatore gcc emette un errore e non compila il file. (Chiedo in termini di gcc, ma questa è più una domanda generica sul linguaggio, non una domanda su gcc, perché penso che sia probabile che altri compilatori si comportino in modo simile).

Qual è la spiegazione di questo comportamento?

    
posta yoyo_fun 04.10.2017 - 12:36
fonte

2 risposte

11

In base alle linee guida per la codifica :

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

La variabile locale non ha alcun collegamento. quindi c'è un nome si verifica collisione. Quindi, non è possibile la dichiarazione multipla della variabile locale.

La variabile globale ha un collegamento esterno. Quindi, è possibile una dichiarazione multipla di variabili globali.

    
risposta data 04.10.2017 - 12:41
fonte
8

@msc offre una buona introduzione alle regole alla base di questo comportamento.

I noticed that if I declare a global variable multiple times the compiler does not even output a warning.

C ha tre tipi di dichiarazioni globali per gli oggetti, vale a dire quelli che sono (e sto superando static qui):

  1. dichiarazioni che non sono definizioni - extern int a;
  2. dichiarazioni che sono anche definizioni - int a = 3; o extern int a = 3;
  3. definizioni provvisorie - int a;

Dichiarazioni multiple di tipo 1 e amp; 3 sono consentiti, mentre è consentita al massimo una definizione (tipo 2).

What is the explanation for this behavior?

Se stai anche chiedendo della motivazione per queste regole, è il supporto per compilazione separata . (Vedi unità di traduzione ).

Per suddividere un programma in più file compilati separatamente, abbiamo bisogno di alcune funzionalità, ovvero (a) essere in grado di dichiarare senza necessariamente definire , e, ( b) forward forward .

All'interno di un'unità di traduzione dobbiamo essere in grado di fare riferimento a funzioni e dati globali in un'altra unità di traduzione. E ci piacerebbe anche qualche controllo degli errori, qui, per scoprire definizioni mancanti e definizioni errate di duplicati.

A volte, nella stessa unità di traduzione, dichiariamo un globale e poi lo definiamo in seguito. Questo può accadere se abbiamo bisogno di una dichiarazione anticipata per qualche ragione, o se usiamo un file di intestazione comune (che fornisce dichiarazioni) all'interno dell'unità di traduzione che offre anche definizioni esplicite.

Poiché la compilazione separata in C si applica collegando insieme funzioni e dati globali, queste funzionalità sono necessarie a livello globale ma non a livello locale.

Come @msc sottolinea, nulla di questo è necessario per le variabili locali in quanto non hanno alcun collegamento.

C (come molti altri linguaggi) non fornisce il collegamento per le variabili locali in quanto la lingua non tenta di supportare una singola funzione che copre più unità di traduzione separate.

(Naturalmente, puoi avere una funzione che si estende su più file sorgente, ma non su più unità di traduzione.)

Una definizione provvisoria funziona come una dichiarazione in quanto è consentita in più unità di traduzione (e si combina anche bene con altre dichiarazioni). Tuttavia, se non esiste una definizione (non provvisoria) per l'identificatore nell'intero programma, l'insieme di (una o più) definizioni provvisorie su più unità di traduzione (per un identificatore) viene preso come definizione per l'oggetto il cui inizializzatore è zero.

Ciò può essere implementato inserendoli nella .BSS Sezione con le dimensioni e l'allineamento appropriati; il linker li abbinerà alla definizione vera se trovato, oppure li abbinerà tra loro, dando loro spazio azzerato in BSS.

La nozione di compilazione separata può essere supportata interamente senza la caratteristica di definizioni provvisorie - Penso che le definizioni provvisorie ci siano per lo più per ragioni storiche. (Non sto dicendo che non sono utili, solo se la lingua è stata creata oggi, potrebbe non essere necessaria e quindi non essere offerta.)

    
risposta data 04.10.2017 - 19:41
fonte

Leggi altre domande sui tag