zmienne stałe nie działające w nagłówku

Jeśli zdefiniuję moje stałe zmienności w nagłówku w ten sposób...

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

Otrzymuję następujący błąd

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

Ale jeśli usunę te stałe z nagłówka i umieszczę je w dokumencie, który zawiera nagłówek w ten sposób...

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

It works

Czy ktoś wie, co robię źle ??

Dzięki

Author: Georg Fritzsche, 2010-02-24

10 answers

Problem polega na tym, że definiujesz obiekty z linkami zewnętrznymi w pliku nagłówkowym. Spodziewamy się, że po dołączeniu tego pliku nagłówkowego do wielu jednostek tłumaczeniowych, otrzymasz wiele definicji tego samego obiektu z połączeniem zewnętrznym, co jest błędem.

Właściwy sposób, aby to zrobić, zależy od twoich intencji.

(1) możesz umieścić swoje definicje w pliku nagłówkowym, ale upewnij się, że mają one wewnętrzne połączenie .

In C that would wymagaj wyraźnego static

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

W C++ static jest opcjonalne (ponieważ w C++ const obiekty mają domyślnie wewnętrzne powiązania)

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

(2) można też umieścić zwykłe deklaracje nie definiujące w pliku nagłówkowym i umieścić definicje W Jednym (i tylko jednym) pliku implementacji

Deklaracje w pliku nagłówek muszą zawierać jawne extern i No initializer

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

I definicje w jednym implementacja plik powinien wyglądać następująco

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

(jawne extern w definicjach jest opcjonalne, jeśli powyższe deklaracje poprzedzają definicje w tej samej jednostce tłumaczeniowej).

To, którą metodę wybierzesz, zależy od twoich intencji.

Pierwsza metoda ułatwia kompilatorowi optymalizację kodu, ponieważ widzi rzeczywistą wartość stałej w każdej jednostce tłumaczenia. Ale jednocześnie koncepcyjnie dostajesz osobne, niezależne stałe obiekty w każdej jednostce tłumaczeniowej. Na przykład &PI będzie oceniać pod innym adresem w każdej jednostce tłumaczenia.

Druga metoda tworzy prawdziwie globalne stałe, tzn. unikalne obiekty stałe, które są współdzielone przez cały program. Na przykład &PI będzie oceniać pod tym samym adresem w każdej jednostce tłumaczenia. Ale w tym przypadku kompilator widzi tylko rzeczywiste wartości w jednej i tylko jednej jednostce tłumaczenia, co może utrudnić optymalizację.

 123
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-01 01:11:16

extern oznacza to, że 'prawdziwa' definicja zmiennej znajduje się gdzie indziej, a kompilator powinien ufać, że rzeczy będą się łączyć w czasie połączenia. Posiadanie definicji w jednej linii z extern jest dziwne i jest tym, co zmaga się z Twoim programem. Jeśli chcesz, aby były extern, po prostu zdefiniuj je dokładnie raz gdzie indziej w swoim programie.

 8
Author: Carl Norum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:02:55

Klasa przechowywania dla nich jest prawie na pewno przyczyną problemu, który widzisz. Jeśli go usuniesz, kod prawdopodobnie będzie w porządku (przynajmniej pod tym względem).

Edit: właśnie zauważyłem, że otagowałeś to jako C i C++. Pod tym względem C i C++ są naprawdę bardzo różne (ale z komunikatów o błędach, najwyraźniej kompilujesz jako C++, a nie C). W C++, chcesz usunąć extern, ponieważ (domyślnie) zmienne const mają klasę przechowywania static. To znaczy każdy plik źródłowy (Jednostka tłumaczenia) otrzyma własną "kopię" zmiennej i nie będzie konfliktu między definicjami w różnych plikach. Ponieważ (prawdopodobnie) używasz tylko wartości, nie traktując ich jako zmiennych, posiadanie wielu "kopii" niczego nie zaszkodzi-żadna z nich nie zostanie przydzielona przestrzeń dyskowa.

W C, extern jest raczej inne, a usunięcie extern nie zrobi żadnej rzeczywistej różnicy, ponieważ będą one domyślnie extern. W takim przypadku naprawdę musisz zainicjalizuj zmienne dokładnie w jednym miejscu i zadeklaruj je w nagłówku. Alternatywnie, możesz dodać static klasę pamięci, którą C++ będzie dodawać domyślnie, gdy / jeśli usuniesz extern z nagłówka.

 5
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:09:28

Wygląda na to, że plik nagłówka jest dołączany wiele razy. Musisz dodać strażników.

Na górze KAŻDEGO pliku nagłówkowego powinieneś mieć coś w stylu:

#ifndef MY_HEADER_FILE_NAME_H
#define MY_HEADER_FILE_NAME_H

...

// at end of file
#endif

Jeśli używasz g++ lub MSVC, możesz po prostu dodać:

#pragma once

Na górze KAŻDEGO pliku nagłówkowego, ale nie jest on w 100% przenośny.

Ponadto nie należy definiować stałych w plikach nagłówkowych, tylko deklarować je:

// In header file
extern const int my_const;


// In one source file
const int my_const = 123;
 2
Author: Peter Alexander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:04:05

Problem polega na tym, że inicjalizujesz zmienne w pliku nagłówkowym ; tworzy to deklarację definiującą , która jest powtarzana w każdym pliku zawierającym ten nagłówek,stąd błąd wielokrotnej definicji.

Chcesz nie -definiującą deklarację (bez inicjalizacji) w pliku nagłówkowym i umieść definiującą deklarację w jednym z plików implementacji.

 2
Author: John Bode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:59:25

Wiele błędnych odpowiedzi poniżej. Te, które są poprawne, to te, które każą Ci usunąć extern, jak powiedział sellibitze w swoim komentarzu, są poprawne.

Ponieważ są one zadeklarowane const, nie ma problemu z definicją w nagłówku. C++ będzie wstawiać const dla typu wbudowanego, chyba że spróbujesz pobrać jego adres (wskaźnik do const), w którym to przypadku utworzy on instancję za pomocą połączenia static, możesz wtedy również uzyskać wiele instancji w oddzielnych Moduły, ale jeśli nie oczekujesz, że wszystkie wskaźniki do tego samego const będą miały ten sam adres, nie jest to problemem.

 2
Author: Clifford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 21:01:10

Musisz zadeklarować kontanty w nagłówku, a następnie zdefiniować je w jednym z plików kodu. Jeśli nie zadeklarujesz ich nigdzie, wtedy wystąpi błąd linkera, gdy próbuje powiązać deklarację z rzeczywistą definicją. Możesz także użyć poleceń # ifdef, aby mieć jedną definicję w nagłówku.

Upewnij się, że są zadeklarowane w nagłówku, który jest dołączany przez wszystkich, którzy ich potrzebują i upewnij się, że są zdefiniowane dokładnie raz.

Jakub

 1
Author: TheJacobTaylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:02:28

Jeśli chcesz zdefiniować stałe w plikach nagłówkowych, użyj static const. Jeśli użyjesz extern, linker ma prawo narzekać na wiele definicji, ponieważ każdy plik źródłowy, w tym plik źródłowy, dostarczy pamięci dla zmiennej, jeśli przypiszesz wartość.

 1
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:03:39

W deklarowaniu global const w nagłówku powoduje, że każda jednostka kompilacji zawierająca ten hader będzie miała własne definicje globalne definicje o tej samej nazwie. Więc linker tego nie lubi.

Jeśli naprawdę potrzebujesz ich w nagłówku, prawdopodobnie powinieneś zadeklarować je jako statyczne.

 0
Author: lollinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-24 19:04:26

Stare pytanie, rzeczywiście, ale brakuje jednej użytecznej odpowiedzi.

Możliwe jest nakłonienie MSVC do zaakceptowania stałych statycznych w nagłówkach, po prostu zawijając je w "atrapowy" szablon klasy:

template <typename Dummy = int>
struct C {
     static const double Pi;
};

template <typename Dummy = int>
const double C<Dummy>::Pi = 3.14159;

Teraz, C:: PI można uzyskać dostęp z innego miejsca. Żadna redefinicja nie narzeka; stała jest bezpośrednio dostępna w każdej jednostce kompilacji bez wymyślnej optymalizacji czasu łącza. Makro może być rozwijane w celu dalszego ulepszenia tego podejścia (nawet jeśli makra są złe).

 0
Author: oakad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-24 04:31:56