C++ 常量变量在标题中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2328671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
constant variables not working in header
提问by numerical25
if I define my constant varibles 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 those constants from the header and put them in the document that is including the header like this...
但是如果我从标题中删除这些常量并将它们放在包含像这样的标题的文档中......
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
It works
有用
Does anyone have Idea what I might be doing wrong ??
有没有人知道我可能做错了什么?
Thanks
谢谢
回答by AnT
The problem is that you defineobjects with external linkage in header file. Expectedly, once you include that header file into multiple translation units, you'll get multiple definitions of the same object with external linkage, which is an error.
问题是您在头文件中定义了具有外部链接的对象。预计,一旦您将该头文件包含到多个翻译单元中,您将获得具有外部链接的同一对象的多个定义,这是一个错误。
The proper way to do it depends on your intent.
正确的方法取决于您的意图。
You can put your definitions into the header file, but make sure that they have internallinkage.
In C that would require 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
is optional (because in C++const
objects have internal linkage by default)const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f;
Or you can put mere non-defining declarationsinto the header file and put the definitionsinto one (and only one) implementation file
The declarations in the headerfile must include an explicit
extern
and no initializerextern const double PI; extern const double PI_under_180; extern const double PI_over_180;
and definitions in one implementationfile should look as follows
const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f;
(explicit
extern
in the definitions is optional, if the above declarations precede the definitions in the same translation unit).
您可以将定义放入头文件中,但要确保它们具有内部链接。
在 C 中,这需要一个明确的
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;
在 C++ 中
static
是可选的(因为在 C++ 中const
对象默认具有内部链接)const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f;
或者,您可以仅将非定义声明放入头文件中,并将定义放入一个(且仅一个)实现文件中
头文件中的声明必须包含显式
extern
且无初始化程序extern const double PI; extern const double PI_under_180; extern const double PI_over_180;
一个实现文件中的定义应如下所示
const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180 = PI/180.0f;
(
extern
如果上述声明位于同一翻译单元中的定义之前,则定义中的显式是可选的)。
Which method you will choose depends on your intent.
您将选择哪种方法取决于您的意图。
The first method makes it easier for the compiler to optimize the code, since it can see the actual value of the constant in each translation unit. But at the same time conceptually you get separate, independent constant objects in every translation unit. For example, &PI
will evaluate to a different address in each translation unit.
第一种方法使编译器更容易优化代码,因为它可以看到每个翻译单元中常量的实际值。但同时在概念上你会在每个翻译单元中获得单独的、独立的常量对象。例如,&PI
将评估为每个翻译单元中的不同地址。
The second method creates truly globalconstants, i.e. unique constant objects that are shared by the entire program. For example, &PI
will evaluate to the same address in each translation unit. But in this case the compiler can only see the actual values in one and only one translation unit, which might impede optimizations.
第二种方法创建真正的全局常量,即整个程序共享的唯一常量对象。例如,&PI
将评估为每个翻译单元中的相同地址。但在这种情况下,编译器只能看到一个且只有一个翻译单元中的实际值,这可能会妨碍优化。
Starting from C++17 you get the third option, which sort of combines "the best of both worlds": inline variables. Inline variables can be safely defined in header files despite having external linkage
从 C++17 开始,您将获得第三个选项,它结合了“两全其美”:内联变量。尽管具有外部链接,但可以在头文件中安全地定义内联变量
inline extern const double PI = 3.1415926535;
inline extern const double PI_under_180 = 180.0f / PI;
inline extern const double PI_over_180 = PI/180.0f;
In this case you get a named constant object whose initializer value is visible in all translation units. And at the same time the object has external linkage, i.e. it has a global address identity (&PI
is the same in all translation units).
在这种情况下,您将获得一个命名常量对象,其初始化值在所有翻译单元中都是可见的。并且同时对象具有外部链接,即它具有全局地址标识(&PI
在所有翻译单元中都相同)。
Granted, something like that might only be necessary for some exotic purposes (most use cases in C++ call for the first variant), but the feature is there.
诚然,类似的东西可能只在某些特殊目的下才需要(C++ 中的大多数用例都调用第一个变体),但该功能就在那里。
回答by Carl Norum
extern
means the 'real' definition of the variable is elsewhere, and the compiler should trust that things will hook up at link time. Having the definition inline with the extern
is weird and is what's munging up your program. If you want to have them be extern
, just define them exactly onceelsewhere in your program.
extern
意味着变量的“真实”定义在别处,编译器应该相信事情会在链接时连接起来。将定义与 内联extern
是很奇怪的,这会破坏您的程序。如果您想拥有它们extern
,只需在程序中的其他地方精确定义一次即可。
回答by Jerry Coffin
The extern
storage class for them is almost certainly the cause of the problem you're seeing. If you remove it, the code will probably be fine (at least in this respect).
extern
它们的存储类几乎可以肯定是您所看到的问题的原因。如果您删除它,代码可能会很好(至少在这方面)。
Edit: I just noticed that you've tagged this as both C and C++. In this respect C and C++ are really quite different (but from the error messages, you're apparently compiling as C++, not C). In C++, you want to remove the extern
, because (by default) const
variables have the static
storage class. That means each source file (translation unit) will get its own "copy" of the variable, and there won't be any conflict between definitions in different files. Since you're (probably) only using the values, not treating them as variables, having multiple "copies" won't hurt anything -- none of them will be allocated storage space.
编辑:我刚刚注意到您已将其标记为 C 和 C++。在这方面,C 和 C++ 确实非常不同(但从错误消息来看,您显然是编译为 C++,而不是 C)。在 C++ 中,您要删除extern
,因为(默认情况下)const
变量具有static
存储类。这意味着每个源文件(翻译单元)将获得自己的变量“副本”,并且不同文件中的定义之间不会有任何冲突。由于您(可能)只使用这些值,而不是将它们视为变量,因此拥有多个“副本”不会有任何伤害——它们都不会被分配存储空间。
In C, extern
is rather different, and removing the extern
won't make any real difference, because they'll be extern
by default. In this case, you really need to initialize the variables in exactly one place, and declare them extern in the header. Alternatively, you can add the static
storage class that C++ will add by default when/if you remove the extern
from the header.
在 C 中,extern
则完全不同,删除extern
不会产生任何真正的区别,因为extern
默认情况下它们将是。在这种情况下,您确实需要在一个地方初始化变量,并在标头中将它们声明为 extern。或者,您可以添加static
C++ 将在/如果extern
从标头中删除时默认添加的存储类。
回答by John Bode
The problem is that you are initializing the variables in the header file; this creates a definingdeclaration, which is repeated in every file that includes that header,hence the multiple definition error.
问题是您正在初始化头文件中的变量;这会创建一个定义声明,该声明在包含该头文件的每个文件中都会重复,因此会出现多重定义错误。
You want a non-defining declaration (no initializer) in the header file, and put the defining declaration in oneof the implementation files.
你想要一个无头文件-定义声明(没有初始化),并把定义声明在一个执行文件。
回答by Clifford
A lot of incorrect responses below. The ones that are correct are the ones telling you to remove the extern
as sellibitze has also said in his comment are correct.
下面有很多不正确的回答。正确的是那些告诉你删除的人,extern
正如sellibitze在他的评论中所说的那样是正确的。
Because these are declared const, there is no problem having the definition in the header. C++ will inline a const for a built in type unless you attempt to take its address (a pointer to a const) in which case it will instantiate it with static
linkage, you may then also get multiple instantiations in separate modules, but unless you expect all pointers to the same const to have the same address, this is not a problem.
因为这些被声明为 const,所以在头文件中定义是没有问题的。C++ 将内联一个内置类型的常量,除非你试图获取它的地址(一个指向常量的指针),在这种情况下它会用static
链接实例化它,然后你也可以在单独的模块中获得多个实例化,但除非你期望所有指向相同 const 的指针具有相同的地址,这不是问题。
回答by Christoph
If you want to define constants in header files, use static const
. If you use extern
, the linker is right to complain about multiple definitions because each including source file will supply memory for the variable if you assign a value.
如果要在头文件中定义常量,请使用static const
. 如果您使用extern
,链接器会抱怨多个定义是正确的,因为如果您分配一个值,每个包含的源文件将为变量提供内存。
回答by Peter Alexander
It looks like that header file is getting included multiple times. You need to add guards.
看起来该头文件被多次包含在内。你需要添加守卫。
At the top of each header file you should have 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 then you can just add:
如果您使用的是 g++ 或 MSVC,那么您只需添加:
#pragma once
At the top of each header file, but that isn't 100% portable.
在每个头文件的顶部,但这不是 100% 可移植的。
Also, you shouldn't define constants in header files, only declare them:
另外,你不应该在头文件中定义常量,只声明它们:
// In header file
extern const int my_const;
// In one source file
const int my_const = 123;
回答by TheJacobTaylor
You need to declare the contants in the header and then define them in one of your code files. If you do not declare them anywhere, then there is a linker error when it tries to tie the declaration to the actual definition. You can also get away with using #ifdef statements to have one definition within the header.
您需要在标头中声明常量,然后在您的代码文件之一中定义它们。如果你没有在任何地方声明它们,那么当它试图将声明与实际定义联系起来时就会出现链接器错误。您还可以使用 #ifdef 语句在标题中包含一个定义。
Make sure they are declared in a header that is included by everyone that needs them and make sure they are defined exactly once.
确保它们在需要它们的每个人都包含的标头中声明,并确保它们只定义一次。
Jacob
雅各布
回答by lollinus
in declaring global const within header causes that each compilation unit including this hader will have own definitions global definitions with the same name. Then linker does not like that.
在头文件中声明 global const 导致每个编译单元包括这个 hader 将有自己的同名定义全局定义。然后链接器不喜欢那样。
If You really need these in header then probably You should declare them as static.
如果您真的需要在标题中使用这些,那么您可能应该将它们声明为静态的。
回答by oakad
An old question, indeed, but one useful answer is missing.
确实是一个老问题,但缺少一个有用的答案。
It is possible to trick MSVC into accepting static constants in headers simply by wrapping those in a "dummy" class template:
只需将它们包装在“虚拟”类模板中,就可以诱使 MSVC 接受标头中的静态常量:
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 accessed from elsewhere. No redefinition complains; constant is directly accessible in each compilation units without fancy link time optimization. Macro can be rolled out to further prettify this approach (even though macros are evil).
现在,可以从其他地方访问 C<>::PI。没有重新定义的抱怨;常量可在每个编译单元中直接访问,无需花哨的链接时间优化。可以推出宏以进一步美化这种方法(即使宏是邪恶的)。