2012-10-19 6 views
13

La norma sembra implicare che non v'è alcun limite al numero di definizioni di una variabile se non è ODR-utilizzato (§3.2/3):Se non utilizzo una variabile, posso avere più definizioni di essa tra le unità di traduzione?

Ogni programma deve contenere esattamente un definizione di ogni funzione non in linea o variabile che è odr-usata in quel programma; nessuna diagnostica richiesta.

Si fa dire che qualsiasi variabile non può essere definita più volte all'interno di un'unità di traduzione (§3.2/1):

Nessuna unità traduzione deve contenere più di una definizione di qualsiasi variabile, funzione , tipo di classe, tipo di enumerazione o modello.

Ma non riesco a trovare una restrizione per le variabili non odr-utilizzate in tutto il programma. Allora, perché non posso compilare qualcosa di simile al seguente:

// other.cpp 
int x; 

// main.cpp 
int x; 
int main() {} 

compilazione e collegamento questi file con g ++ 4.6.3, ottengo un errore di linker per multiple definition of 'x'. Per essere onesti, mi aspetto questo, ma dal momento che lo x non è usato da nessun'altra parte (per quanto ne so io), non riesco a vedere come lo standard lo limiti. O è un comportamento indefinito?

risposta

11

Il programma viola le regole di collegamento. C++ 11 §3.5 [base.link]/9 stati:

due nomi che sono gli stessi e che sono dichiarati in diversi ambiti deve denotare la stessa variabile, funzione, tipo, enumeratore, modello o dello spazio dei nomi se

  • sia i nomi hanno un collegamento esterno oppure entrambi i nomi hanno un collegamento interno e sono dichiarati nella stessa unità di traduzione; e

  • entrambi i nomi si riferiscono a membri dello stesso spazio dei nomi o ai membri, non per eredità, della stessa classe; e

  • quando entrambi i nomi indicano funzioni, gli elenchi di tipi di parametri delle funzioni sono identici; e

  • quando entrambi i nomi indicano modelli di funzioni, le firme sono le stesse.

(ho citato il paragrafo completo, per riferimento. I secondi due proiettili non si applicano qui.)

Nel programma, ci sono due nomi x, che sono gli stessi. Sono dichiarati in ambiti diversi (in questo caso sono dichiarati in diverse unità di traduzione). Entrambi i nomi hanno un collegamento esterno e entrambi i nomi si riferiscono ai membri dello stesso spazio dei nomi (lo spazio dei nomi globale).

Questi due nomi non indicano la stessa variabile. La dichiarazione int x; definisce una variabile. Perché ci sono due definizioni del genere nel programma, ci sono due variabili nel programma. Il nome "x" in una unità di traduzione denota una di queste variabili; il nome "x" nell'altra unità di traduzione indica l'altro. Pertanto, il programma è mal formato.

+2

Come si arriva alla conclusione che i due nomi 'x' non denotano la stessa variabile? – ecatmur

+1

@ecatmur: Ci sono due variabili perché ci sono due definizioni: 'int x;' definisce una variabile con durata di memorizzazione statica. Ci sono due definizioni di questo tipo, quindi ci sono due variabili.Se il programma fosse modificato come suggerito da Luc Danton, ci sarebbe solo una variabile perché ci sarebbe solo una definizione ('extern int x;' non è una _definizione_ di 'x', è solo una _declaration_). –

+0

Se invece di 'int x;' le dichiarazioni hanno la forma 'class y {};' o 'namespace z {}' (entrambe le definizioni), i nomi 'y' e' z' denoterebbero rispettivamente lo stesso tipo o spazio dei nomi . In che modo la variabile 'x' è diversa? – ecatmur

0

Non ci sono errori nella compilazione di questo, l'errore è nel suo collegamento. Per impostazione predefinita, la variabile globale o le funzioni sono pubbliche per altri file (avere lo spazio di archiviazione extern) quindi alla fine quando il linker desidera collegare il codice, vede due definizioni per x e non è possibile selezionarne uno, quindi se non si utilizza x di main.cpp in other.cpp e vice-verse li rendono statico (che significa visibile solo per il file che la contengono)

// other.cpp 
static int x; 

// main.cpp 
static int x; 
1

Se norma non dice nulla circa le definizioni delle variabili non utilizzate allora non si può implicare che non ci può essere multipli:

Un comportamento indefinito può anche essere utile d quando questo standard internazionale omette la descrizione di qualsiasi definizione esplicita del comportamento .

Così può compilare ed eseguire bene o può arrestare durante la traduzione con messaggio di errore o può bloccare il runtime ecc

EDIT: Vedere James McNellis rispondere allo standard anzi in realtà ha delle regole su di esso.

+0

Il programma non presenta un comportamento non definito; è mal formato. Viola una regola semantica diagnosticabile. –

+0

@James sì, è mal formato, ma quello che ho detto vale ancora, se standard omette di descrivere qualcosa, allora non è sempre definito cosa succede, il lettore potrebbe non implicare solo una cosa casuale. –

5

Hai ragione che lo standard è in difetto a questo proposito. Ho la sensazione che questo caso rientri nel divario tra 3.2p1 (al massimo una definizione per unità di traduzione, come nella tua domanda) e 3.2p6 (che descrive come classi, enumerazioni, funzioni inline e vari modelli possono avere definizioni duplicate tra unità di traduzione).

Per confronto, in C, 6.9p5 richiede che (mia enfasi):

Una definizione esterna è una dichiarazione esterna che è anche una definizione di una funzione (diverso da una definizione in linea) o un oggetto. Se un identificatore dichiarato con collegamento esterno viene utilizzato in un'espressione (diverso da come parte dell'operando di un operatore sizeof o _Alignof il cui risultato è una costante intera), da qualche parte nell'intero programma ci deve essere esattamente una definizione esterna per l'identificatore; altrimenti non ci deve essere più di uno.