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).