La parola chiave "statico" in C ha due significati fondamentalmente diversi.
Ambito di limitazione
In questo contesto, "static" si accoppia con "extern" per controllare l'ambito di una variabile o il nome di una funzione. Statico fa sì che il nome della variabile o della funzione sia disponibile solo all'interno di una singola unità di compilazione e disponibile solo per il codice esistente dopo la dichiarazione / definizione all'interno del testo dell'unità di compilazione.
Questa stessa limitazione in realtà significa solo qualcosa se e solo se hai più di una unità di compilazione nel tuo progetto. Se hai una sola unità di compilazione, fa comunque cose ma quegli effetti sono per lo più inutili (a meno che non ti piaccia scavare in file oggetto per leggere ciò che il compilatore ha generato.)
Come notato, questa parola chiave in questo contesto si accoppia con la parola chiave "extern", che fa il contrario - rendendo la variabile o il nome della funzione collegabile con lo stesso nome trovato in altre unità di compilazione. Quindi puoi considerare "statico" come se fosse necessario trovare la variabile o il nome nell'attuale unità di compilazione, mentre "extern" consente il collegamento tra unità di compilazione incrociata.
Durata statica
La durata statica significa che la variabile esiste per tutta la durata del programma (per quanto lunga sia.) Quando si utilizza "statico" per dichiarare / definire una variabile all'interno di una funzione, significa che la variabile viene creata prima del suo primo utilizzo ( il che significa, ogni volta che l'ho sperimentato, che la variabile viene creata prima dell'inizio di main () e non viene distrutta in seguito. Nemmeno quando l'esecuzione della funzione è completata e ritorna al suo chiamante. E proprio come le variabili di durata statica dichiarate al di fuori delle funzioni, vengono inizializzate nello stesso momento - prima che main () inizi - su uno zero semantico (se non viene fornita l'inizializzazione) o su un valore esplicito specificato, se indicato.
Ciò è diverso dalle variabili di funzione di tipo "auto", che vengono create nuove (o, come se fossero nuove) ogni volta che la funzione viene immessa e quindi vengono distrutte (o, come se fossero state distrutte) all'uscita della funzione.
A differenza dell'impatto dell'applicazione di "statico" su una definizione variabile al di fuori di una funzione, che influisce direttamente sul suo ambito, dichiarare una variabile di funzione (all'interno di un corpo di funzione, ovviamente) come "statico" non ha alcun impatto sul suo ambito. L'ambito è determinato dal fatto che è stato definito all'interno di un corpo di funzione. Le variabili di durata statiche definite all'interno delle funzioni hanno lo stesso ambito delle altre variabili "auto" definite all'interno dei corpi delle funzioni - ambito delle funzioni.
Sommario
Quindi la parola chiave "statica" ha contesti diversi con ciò che equivale a "significati molto diversi". Il motivo per cui è stato utilizzato in due modi, come questo, è stato quello di evitare di usare un'altra parola chiave. (Ci fu una lunga discussione a riguardo.) Si pensava che i programmatori potessero tollerare l'uso e il valore di evitare l'ennesima parola chiave nella lingua era più importante (rispetto agli argomenti altrimenti).
(Tutte le variabili dichiarate al di fuori delle funzioni hanno una durata statica e non hanno bisogno della parola chiave "statica" per renderla vera. Quindi questo tipo di parola chiave liberata per essere usata lì significa qualcosa di completamente diverso: "visibile solo in una singola compilazione unità. "È una specie di hack.)
Nota specifica
carattere statico volatile senza segno PORTB @ 0x06;
La parola "statico" qui dovrebbe essere interpretata nel senso che il linker non tenterà di far corrispondere più occorrenze di PORTB che possono essere trovate in più di una unità di compilazione (supponendo che il codice ne abbia più di una).
Utilizza una sintassi speciale (non portatile) per specificare la "posizione" (o il valore numerico dell'etichetta che di solito è un indirizzo) di PORTB. Quindi al linker viene assegnato l'indirizzo e non è necessario trovarne uno. Se avessi due unità di compilazione che usano questa linea, ognuna finirebbe per indicare lo stesso posto. Quindi non c'è bisogno di etichettarlo come "esterno", qui.
Se avessero usato "esternamente", ciò avrebbe potuto costituire un problema. Il linker sarebbe quindi in grado di vedere (e tenterebbe di abbinare) più riferimenti a PORTB trovati in più compilazioni. Se tutti specificano un indirizzo come questo, e gli indirizzi NON sono gli stessi per qualche motivo [errore?], Allora cosa dovrebbe fare? Lamentarsi? O? (Tecnicamente, con 'extern' la regola empirica sarebbe che solo UNA unità di compilazione specifica il valore e le altre no.)
È solo più facile etichettarlo come "statico", evitando di preoccupare il linker dei conflitti e semplicemente dare la colpa per eventuali errori per indirizzi errati su chiunque abbia cambiato l'indirizzo in qualcosa che non dovrebbe essere.
In entrambi i casi, la variabile viene considerata come "a vita statica". (E 'volatile'.)
Una dichiarazione non è una definizione , ma tutte le definizioni sono dichiarazioni
In C, una definizione crea un oggetto. Lo dichiara anche. Ma una dichiarazione di solito (vedi la nota in basso) non crea un oggetto.
Di seguito sono riportate definizioni e dichiarazioni:
static int a;
static int a = 7;
extern int b = 5;
extern int f() { return 10; }
Le seguenti non sono definizioni, ma solo dichiarazioni:
extern int b;
extern int f();
Si noti che le dichiarazioni non creano un oggetto reale. Dichiarano solo i dettagli al riguardo, che il compilatore può quindi utilizzare per aiutare a generare il codice corretto e per fornire messaggi di avviso e di errore, come appropriato.
Sopra, dico "di solito", in modo consapevole. In alcuni casi, una dichiarazione può creare un oggetto ed è quindi promossa a una definizione dal linker (mai dal compilatore). Quindi, anche in questo raro caso, il compilatore C pensa ancora che la dichiarazione sia solo una dichiarazione. È la fase del linker che rende necessarie eventuali promozioni di alcune dichiarazioni. Tienilo bene a mente.
Negli esempi precedenti, se dovesse risultare che ci sono solo dichiarazioni per un "extern int b;" in tutte le unità di compilazione collegate, quindi il linker ha la responsabilità di creare una definizione. Tieni presente che si tratta di un evento di collegamento temporale. Il compilatore è completamente inconsapevole, durante la compilazione. Può essere determinato solo al momento del collegamento, se viene promossa una dichiarazione di questo tipo.
Il compilatore è consapevole che "static int a;" non può essere promosso dal linker al momento del collegamento, quindi in realtà questa è una definizione al momento della compilazione .