@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):
- dichiarazioni che non sono definizioni -
extern int a;
- dichiarazioni che sono anche definizioni -
int a = 3;
o extern int a = 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.)