2011-01-22 17 views
20

Da External Variables Wiki:Dichiarazione o definizione in C

Se sono presenti né la parola chiave extern né un valore di inizializzazione, la dichiarazione possono essere sia una dichiarazione o di una definizione. Spetta al compilatore per analizzare i moduli del programma e decidere.

non era in grado di cogliere appieno il significato di questa affermazione rispetto a C. Ad esempio, implica che:

int i; 

non è necessariamente una dichiarazione (come ho assumendo fino ora), ma potrebbe essere una definizione così (per definizione della definizione & Dichiarazione sulla stessa pagina web, senza sottintesi)?

In poche parole, è la dichiarazione di cui sopra: a. solo una dichiarazione, oppure b. dichiarazione + definizione?

Riferimento: Variable declaration and definition

Riassunto delle risposte ricevute:

      Declaration Definition Tentative Definition Initialized 
int i; (inside a block) Yes   Yes    No    No 
int i=5; (inside a block) Yes   Yes    No    Yes(to 5) 
int i; (otherwise)   Yes   No    Yes    Yes(to 0) 
extern int i;    Yes   No    No    No 


All definitions are declarations but not vice-versa. 

risposta

13

Lo standard C dice che

Una definizione di un identificatore è una dichiarazione di tale identificatore che: per un oggetto, fa sì che lo stoccaggio da assegnare per l'oggetto (...)

Le definizioni comprendono dichiarazioni, ovvero ogni definizione è necessariamente una dichiarazione, quindi non ha senso dire che

int i; 

non è una dichiarazione. È è una dichiarazione che capita anche di essere una definizione. O è una definizione, quindi una dichiarazione.

+7

Tuttavia, è una buona idea tenere a mente che non tutte le dichiarazioni sono definizioni. –

15

Supponendo che sia nell'ambito di file si tratta di un 'tentativo di definizione'. Da 6.9.2/2 "Definizioni degli oggetti esterni":

Una dichiarazione di un identificatore per un oggetto che ha presentare portata senza un inizializzatore, e senza un identificatore classe di archiviazione o con l'identificatore classe di archiviazione statica , costituisce una definizione provvisoria . Se un'unità traduzione contiene una o più definizioni indicative per un identificatore , e l'unità di traduzione non contiene definizione esterna per questo identificatore, allora il comportamento è esattamente come se l'unità traduzione contiene una dichiarazione ambito di file di tale identificatore, con la tipo composito a partire dalla fine della unità di traduzione, con un inizializzatore uguale a 0.

Ciò significa che sarebbe valida avere anche quanto segue nella unità di traduzione:

int i = 42; 

dal che decla razione ha un inizializzatore esplicito, è la definizione della variabile i.

quanto riguarda se la dichiarazione è in un ambito blocco, la norma dice seguenti (6.2.2/2 "Collegamenti di identificatori"):

Ogni dichiarazione di un identificatore con senza denota linkage un'entità unica.

...

(paragrafo 6) I seguenti identificatori non hanno alcun legame: ...a identificatore di ambito di blocco per un oggetto dichiarato senza l'identificatore di classe di memoria extern.

Quindi in ambito di blocco, la dichiarazione sarebbe anche una definizione.

+0

Supponendo che si trovi all'interno di un blocco (non nell'ambito di un file) ...? –

+0

@crypto: aggiornato la risposta per coprire una dichiarazione dell'ambito di blocco. –

+0

Grazie per la risposta dettagliata. Ho selezionato la risposta di Bavarious perché è più diretta. –

4

Nel contesto di variabili:

  • Una dichiarazione di una variabile è una dichiarazione che descrive come questa variabile assomiglia. Quindi:

    extern int x; 
    

    portata globale si traduce in: "da qualche parte nel codice, c'è una variabile chiamata x che ha tipo int e il collegamento extern Una dichiarazione è necessaria prima che mai riferimento a x (Lo stesso vale per.. . dichiarazioni di funzioni)

  • una definizione è una dichiarazione che crea un'istanza di questa variabile Quindi:.

    int x; 
    

    in ambito globale crea un unico variab le di tipo int con collegamento esterno. Quindi, se si inserisse tale riga in un'intestazione, ogni unità di traduzione che includesse quell'intestazione tenterebbe di creare la propria copia di x, il che è indesiderabile: è per questo che abbiamo solo dichiarazioni nei file di intestazione. Lo stesso vale per le funzioni: se fornite il corpo della funzione, è una definizione.

Inoltre, formalmente, ogni definizione è una sorta di dichiarazione, come ha anche specificare come questa variabile/funzione è simile - quindi se una definizione esiste già in un determinato ambito, non è necessario alcun dichiarazioni aggiuntive per usarlo.

1

Dal spec C99:

Una dichiarazione di un identificatore per un oggetto che ha presentare portata senza un inizializzatore, e senza un identificatore classe di archiviazione o con l'identificatore di storage di classe statica, costituisce un definizione provvisoria.Se un'unità traduzione contiene una o più definizioni indicative per un identificatore , e l'unità di traduzione non contiene definizione esterna per questo identificatore, allora il comportamento è esattamente come se l'unità traduzione contiene una dichiarazione ambito di file di tale identificatore, con la tipo composito a partire dalla fine della unità di traduzione, con un inizializzatore uguale a 0.

Quindi questo è un caso in cui una semplice dichiarazione senza un inizializzatore può essere una dichiarazione.

+0

È possibile aggiungere la risposta a Michael, poiché si fa riferimento alla stessa parte dello standard C99? –

+0

Quella citazione dalle specifiche sta parlando del comportamento del compilatore. Sta dicendo che questo particolare caso di dichiarazione potrebbe finire per essere una definizione. – davep

+0

Sembra che abbia aggiunto la citazione alla sua risposta ... –

1

Come C utilizza i termini:

una "definizione" crea qualcosa (che occupa una sorta di memoria). Descrive anche qualcosa. Ciò significa che una "definizione" è anche una "dichiarazione".

Una "dichiarazione" descrive solo qualcosa. L'idea è che il compilatore debba sapere come costruire il codice che usa la cosa definita altrove. Successivamente, il linker collega quindi l'utilizzo a qualcosa.

dichiarazioni consentono di compilare codice e collegarlo (più tardi) come un passaggio separato.

Problemi correlati