2015-10-18 28 views
19

Considerare il seguente programma. Questo darà errori di compilazione?Qual è la logica dietro le definizioni provvisorie in C?

#include <stdio.h> 
int s=5; 
int s; 
int main(void) 
{ 
    printf("%d",s); 
} 

A prima vista sembra che il compilatore darà errori ridefinizione variabile, ma il programma è perfettamente valida secondo C standard. (Vedi demo dal vivo qui http://ideone.com/Xyo5SY).

Una definizione provvisoria è qualsiasi dichiarazione di dati esterna che non ha alcun identificatore di classe di memoria e nessun inizializzatore.

C99 6.9.2/2

Una dichiarazione di un fi catore per un oggetto che ha fi portata senza un inizializzatore, e senza una classe di archiviazione specifico er o con il classe di archiviazione specifico er statico, costituisce una definizione provvisoria. Se un'unità di traduzione contiene una o più definizioni provvisorie per un identificatore e l'unità di traduzione non contiene alcuna definizione esterna per che identifica, allora il comportamento è esattamente come se la traduzione unità contenga una dichiarazione di ambito di file di quell'identi fi catore, con tipo composito partire dalla fine della unità di traduzione, un inizializzatore uguale a 0.

mia domanda è, ciò che è razionale per consentire definizioni tentativi? C'è qualche uso di questo in C? Perché C consente definizioni provvisorie?

+2

Non credo che ci sei alcuna motivazione preziosi per che a causa C++ non si è mai avuto, tra i tanti altri linguaggi di programmazione. – edmz

risposta

6

Le definizioni provvisorie sono state create come un modo per collegare modelli incompatibili esistenti pre-C89. Questo è coperta a C99 rationale sezione 6.9.2 definizioni oggetto esterno che dice:

Prima C90, implementazioni ampiamente variare per quanto riguarda inoltrare fanno riferimento identificatori con collegamento interno (vedi §6.2.2). Il comitato C89 ha inventato il concetto di definizione provvisoria per gestire questa situazione . Una definizione provvisoria è una dichiarazione che può o meno comportarsi come una definizione: se una definizione effettiva viene trovata più avanti nell'unità di traduzione , la definizione provvisoria si comporta semplicemente come una dichiarazione . In caso contrario, la definizione provvisoria si comporta come una definizione effettiva di . Per motivi di coerenza, le stesse regole si applicano agli identificatori con collegamento esterno, sebbene non siano strettamente necessari .

e sezione 6.2.2 dalla logica C99 dice:

Il modello definizione da utilizzare per oggetti con linkage esterno era un grave problema C89 standardizzazione. Il problema di base era decidere quali dichiarazioni di un oggetto definiscono la memoria per l'oggetto e che fa semplicemente riferimento a un oggetto esistente. Un problema correlato era se sono consentite più definizioni di archiviazione, o solo uno è accettabile. Pre-C89 implementazioni mostra almeno quattro diversi modelli , elencati qui in ordine crescente di restrittività:

+0

Come conosci e comprendi lo standard C & C++ così bene? Sei davvero geniale. – Destructor

+0

@PravasiMeet Lo conosco bene perché passo molto tempo a leggere lo standard e i relativi documenti e domande. Si tratta solo di pratica ed esperienza. Più esperienza hai, più problemi interessanti avrai a risolvere e si costruisce da lì. –

4

Ecco un esempio di un caso in cui è utile:

void (*a)(); 

void bar(); 
void foo() 
{ 
    a = bar; 
} 

static void (*a)() = foo; 

/* ... code that uses a ... */ 

Il punto chiave è che la definizione di foo deve fare riferimento a, e la definizione di a deve riferirsi a foo. Dovrebbero essere possibili anche esempi simili con strutture inizializzate.

+2

In questo caso specifico, è possibile evitare la necessità di una dichiarazione provvisoria aggiungendo un 'extern' alla prima riga (rendendola solo una dichiarazione). Dove hai davvero bisogno della dichiarazione provvisoria è se vuoi che 'a' sia' statico' (file scope) –

+0

@ChrisDodd: Sì, mi sono perso. Lo cambierò. Grazie. –

+0

No, è un puntatore a funzione. –