Permanent variables not working in the header

if I define my constant variables in my header like this ...

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

I get the following error

 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 

but if I remove these constants from the title and put them in a document that includes a title like this ...

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

Works

Does anyone have an idea what I can do wrong?

thank

+47
c ++ c visual-studio-2008 visual-c ++ visual-studio
Feb 24 '10 at 18:57
source share
10 answers

The problem is that you are defining objects with an external link in the header file. It is expected that after including this header file in several translation units, you will get several definitions of the same object with external communication, which is an error.

The right way to do this depends on your intentions.

(1) You can put your definitions in the header file, but make sure they have an internal link.

In C, which requires an explicit 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; 

In C ++, static optional (because in C ++, const objects have an internal binding by default)

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

(2) Or you can put simple non-information declarations in the header file and put the definitions in one (and only one) implementation file

Declarations in the header file must contain an explicit extern and not initialize

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

and definitions in one implementation file should look like this

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

(explicit extern in definitions is optional if the above declarations precede definitions in the same translation unit).

Which method you choose depends on your intentions.

The first method simplifies the compiler to optimize the code, because it can see the actual value of the constant in each translation unit. But at the same time, conceptually, you get separate independent permanent objects in each translation unit. For example, &PI will evaluate a different address in each translation unit.

The second method creates truly global constants, i.e. unique permanent objects that are shared by the entire program. For example, &PI will evaluate the same address in each translation unit. But in this case, the compiler can see only the actual values ​​in one and only one translation unit, which can complicate the optimization.

+112
Feb 24 '10 at 19:07
source share

extern means that the "real" definition of the variable is in a different place, and the compiler must trust that everything will be connected with the connection time. Having an inline definition with extern is strange, and this is what interferes with your program. If you want them to be extern , just define them exactly once in another place in your program.

+8
Feb 24 '10 at 19:02
source share

The extern storage class for them is almost certainly the cause of the problem you see. If you delete it, the code will probably be fine (at least in this regard).

Edit: I just noticed that you marked this as C and C ++. In this regard, C and C ++ are really quite different (but from the error messages you seem to be compiling as C ++, not C). In C ++, you want to remove extern because (by default) const variables have a static storage class. This means that each source file (translation unit) will receive its own β€œcopy” of the variable, and there will be no conflict between the definitions in different files. Since you (possibly) use only values, not treating them as variables, the presence of several β€œcopies” will not harm anything - none of them will be allocated storage space.

In C, extern quite different, and deleting extern will not make any real difference, because by default they will be extern . In this case, you really need to initialize the variables in one place and declare them extern in the header. Alternatively, you can add a static storage class, which C ++ will add by default when / if you remove extern from the header.

+5
Feb 24 '10 at 19:01
source share

It looks like the header file is included several times. You need to add guards.

At the top of each header file should be something like:

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

If you are using g ++ or MSVC, you can simply add:

 #pragma once 

At the top of each header file, but not 100% portable.

In addition, you should not define constants in header files, just declare them:

 // In header file extern const int my_const; // In one source file const int my_const = 123; 
+2
Feb 24 '10 at 19:04
source share

The problem is that you are initializing the variables in the header file; this creates a defining declaration, which is repeated in every file that includes this header, and therefore in a multiple definition error.

In the header file, you want to specify a non-defining declaration (without an initializer) and place the defining declaration in one of the implementation files.

+2
Feb 24 '10 at 19:59
source share

Many incorrect answers below. Those who tell you to delete extern are correct, as sellibitze also said that his comments are correct.

Since they are declared as const, there is no problem with the definition in the header. C ++ will inline const for the inline type, if you do not try to take its address (pointer to a constant), in which case it will create an instance using the static link, you can also get multiple instances in separate modules, but if you expect that all pointers to the same const will have the same address, this is not a problem.

+2
Feb 24 2018-10-21
source share

You need to declare the participants in the header, and then define them in one of the code files. If you don't declare them anywhere, then a linker error occurs when it tries to bind the declaration to the actual definition. You can also get away with #ifdef statements to have one definition inside the header.

Make sure they are declared in the header, which is included by everyone who needs them, and make sure they are defined exactly once.

Jacob

+1
Feb 24 '10 at 19:02
source share

If you want to define constants in header files, use static const . If you use extern , the linker is right to complain about several definitions because each of them includes a source file that will supply the variable's memory if you assign a value.

+1
Feb 24 '10 at 19:03
source share

declaring global const inside the header causes each compilation unit, including this add-on, to have their own definitions of global definitions with the same name. Then the linker does not like it.

If you really need these headers, perhaps you should declare them static.

0
Feb 24 '10 at 19:04
source share

An old question, indeed, but one useful answer is missing.

You can trick MSVC into accepting static constants in the headers by simply wrapping them in a "dummy" class template:

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

Now C <> :: PI can be obtained from another location. No redefinition complains; the constant is directly available in each compilation unit without optimizing the time of the dummy link. Macros can be expanded to further remove this approach (although macros are evil).

0
Oct 24 '13 at 4:31 on
source share



All Articles