variabili costanti che non funzionano nell’intestazione

se definisco il mio costante varibles nel mio header come questo …

extern const double PI = 3.1415926535; extern const double PI_under_180 = 180.0f / PI; extern const double PI_over_180 = PI/180.0f; 

Ottengo il seguente errore

 1>MyDirectX.obj : error LNK2005: "double const PI" ([email protected]@3NB) already defined in main.obj 1>MyDirectX.obj : error LNK2005: "double const PI_under_180" ([email protected]@3NB) already defined in main.obj 1>MyDirectX.obj : error LNK2005: "double const PI_over_180" ([email protected]@3NB) already defined in main.obj 1>MyGame.obj : error LNK2005: "double const PI" ([email protected]@3NB) already defined in main.obj 1>MyGame.obj : error LNK2005: "double const PI_under_180" ([email protected]@3NB) already defined in main.obj 1>MyGame.obj : error LNK2005: "double const PI_over_180" ([email protected]@3NB) already defined in main.obj 

ma se rimuovo quelle costanti dall’intestazione e le metto nel documento che include l’intestazione come questa …

 const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f; 

Funziona

Qualcuno ha idea di cosa potrei fare male ??

Grazie

Il problema è che si definiscono oggetti con collegamento esterno nel file di intestazione. Prevedibilmente, una volta incluso questo file di intestazione in più unità di traduzione, otterrete più definizioni dello stesso object con il collegamento esterno, che è un errore.

Il modo corretto di farlo dipende dal tuo intento.

(1) Puoi inserire le tue definizioni nel file di intestazione, ma assicurati che abbiano un collegamento interno .

In C che richiederebbe una static esplicita

 static const double PI = 3.1415926535; static const double PI_under_180 = 180.0f / PI; static const double PI_over_180 = PI/180.0f; 

In C ++ static è facoltativo (perché in C ++ gli oggetti const hanno il collegamento interno per impostazione predefinita)

 const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f; 

(2) Oppure puoi inserire semplici dichiarazioni non definitive nel file di intestazione e inserire le definizioni in un unico (e solo uno) file di implementazione

Le dichiarazioni nel file di intestazione devono includere un extern esplicito e nessun inizializzatore

 extern const double PI; extern const double PI_under_180; extern const double PI_over_180; 

e le definizioni in un file di implementazione dovrebbero apparire come segue

 const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f; 

(l’ extern esplicito nelle definizioni è facoltativo, se le dichiarazioni precedenti precedono le definizioni nella stessa unità di traduzione).

Quale metodo sceglierai dipende dal tuo intento.

Il primo metodo rende più facile per il compilatore ottimizzare il codice, poiché può vedere il valore effettivo della costante in ogni unità di traduzione. Ma allo stesso tempo concettualmente si ottengono oggetti costanti separati e indipendenti in ogni unità di traduzione. Ad esempio, &PI valuterà un indirizzo diverso in ciascuna unità di traduzione.

Il secondo metodo crea costanti veramente globali , vale a dire oggetti costanti unici condivisi dall’intero programma. Ad esempio, &PI valuterà lo stesso indirizzo in ciascuna unità di traduzione. Ma in questo caso il compilatore può solo vedere i valori effettivi in ​​una sola e sola unità di traduzione, che potrebbe impedire le ottimizzazioni.

extern significa che la definizione “reale” della variabile è altrove, e il compilatore dovrebbe avere fiducia che le cose si colleghino al momento del collegamento. Avere la definizione in linea con l’ extern è strana ed è ciò che sta danneggiando il tuo programma. Se vuoi che siano extern , definiscili esattamente una volta altrove nel tuo programma.

La class di archiviazione extern per loro è quasi certamente la causa del problema che stai vedendo. Se lo rimuovi, il codice probabilmente andrà bene (almeno in questo senso).

Modifica: ho appena notato che hai taggato questo come C e C ++. A questo proposito, C e C ++ sono molto diversi (ma dai messaggi di errore, apparentemente si compila come C ++, non C). In C ++, si desidera rimuovere l’ extern , perché (per impostazione predefinita) le variabili const hanno la class di archiviazione static . Ciò significa che ogni file sorgente (unità di traduzione) riceverà la propria “copia” della variabile e non ci sarà alcun conflitto tra le definizioni in file diversi. Dal momento che stai (probabilmente) solo usando i valori, non considerandoli come variabili, avere più “copie” non danneggerà nulla – a nessuno di loro verrà assegnato spazio di archiviazione.

In C, extern è piuttosto diverso, e rimuovere l’ extern non farà alcuna differenza reale, perché saranno extern di default. In questo caso, è davvero necessario inizializzare le variabili esattamente in un punto e dichiararle esternamente nell’intestazione. In alternativa, è ansible aggiungere la class di archiviazione static che C ++ aggiungerà di default quando / se si rimuove l’ extern dall’intestazione.

Sembra che il file di intestazione sia stato incluso più volte. Devi aggiungere guardie.

Nella parte superiore di ogni file di intestazione dovresti avere qualcosa del tipo:

 #ifndef MY_HEADER_FILE_NAME_H #define MY_HEADER_FILE_NAME_H ... // at end of file #endif 

Se si utilizza g ++ o MSVC, è sufficiente aggiungere:

 #pragma once 

Nella parte superiore di ciascun file di intestazione, ma non è al 100% portatile.

Inoltre, non devi definire le costanti nei file di intestazione, ma solo dichiararli:

 // In header file extern const int my_const; // In one source file const int my_const = 123; 

Il problema è che stai inizializzando le variabili nel file di intestazione ; questo crea una dichiarazione di definizione , che viene ripetuta in ogni file che include quell’intestazione, quindi l’errore di definizione multipla.

Si desidera una dichiarazione non definita (nessun inizializzatore) nel file di intestazione e inserire la dichiarazione di definizione in uno dei file di implementazione.

Molte risposte errate di seguito. Quelli che sono corretti sono quelli che ti dicono di rimuovere l’ extern come sellibitze ha anche detto nel suo commento sono corretti.

Poiché questi sono dichiarati const, non c’è alcun problema ad avere la definizione nell’intestazione. C ++ incorpora un const per un tipo incorporato, a meno che tu non tenti di prendere il suo indirizzo (un puntatore a un const) nel qual caso lo istanzia con static link static , potresti anche ottenere più istanze in moduli separati, ma a meno che non ti aspetti tutti i puntatori allo stesso const per avere lo stesso indirizzo, questo non è un problema.

Devi dichiarare i concorrenti nell’intestazione e poi definirli in uno dei tuoi file di codice. Se non si dichiarano da nessuna parte, allora c’è un errore del linker quando tenta di bind la dichiarazione alla definizione effettiva. Puoi anche usare le istruzioni #ifdef per avere una definizione nell’intestazione.

Assicurati che siano dichiarati in un’intestazione che è inclusa da tutti coloro che ne hanno bisogno e assicurarsi che siano definiti esattamente una volta.

Giacobbe

Se si desidera definire le costanti nei file di intestazione, utilizzare static const . Se si utilizza extern , il linker ha ragione di lamentarsi di più definizioni, perché ogni file sorgente incluso fornirà memoria per la variabile se si assegna un valore.

nel dichiarare il const globale all’interno dell’intestazione fa sì che ciascuna unità di compilazione che include questo hader abbia definizioni globali con lo stesso nome. Quindi il linker non gli piace.

Se hai davvero bisogno di questi nell’intestazione, probabilmente dovresti dichiararli come statici.

Una vecchia domanda, in effetti, ma manca una risposta utile.

È ansible ingannare MSVC nell’accettare le costanti statiche nelle intestazioni semplicemente avvolgendo quelle in un modello di class “fittizio”:

 template  struct C { static const double Pi; }; template  const double C::Pi = 3.14159; 

Ora è ansible accedere a C <> :: PI da un’altra posizione. Nessuna ridefinizione si lamenta; la costante è direttamente accessibile in ogni unità di compilazione senza ottimizzare l’ottimizzazione del tempo di collegamento. La macro può essere estesa per migliorare ulteriormente questo approccio (anche se le macro sono malvagie).