C++ 常量变量在标头中不起作用
如果我在标题中定义常量变量,如下所示C++ 常量变量在标头中不起作用,c++,c,visual-studio,visual-studio-2008,visual-c++,C++,C,Visual Studio,Visual Studio 2008,Visual C++,如果我在标题中定义常量变量,如下所示 extern const double PI = 3.1415926535; extern const double PI_under_180 = 180.0f / PI; extern const double PI_over_180 = PI/180.0f; const double PI = 3.1415926535; const double PI_under_180 = 180.0f / PI; const double PI_over_180
extern const double PI = 3.1415926535;
extern const double PI_under_180 = 180.0f / PI;
extern const double PI_over_180 = PI/180.0f;
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
我得到以下错误
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
但是如果我从标题中删除这些常量,并将它们放在包含标题的文档中,就像这样
extern const double PI = 3.1415926535;
extern const double PI_under_180 = 180.0f / PI;
extern const double PI_over_180 = PI/180.0f;
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
它起作用了
有人知道我可能做错了什么吗
感谢他们的
extern
存储类几乎肯定是您看到的问题的原因。如果删除它,代码可能会很好(至少在这方面)
<>编辑:我注意到你把这个标记为C和C++。在这方面,C++和C++是完全不同的(但是从错误消息来看,你显然是编译为C++,而不是C)。在C++中,您要删除<代码> ExtNe>代码>,因为(默认情况下)<代码> const 变量具有<代码>静态< /代码>存储类。这意味着每个源文件(翻译单元)将获得自己的变量“副本”,并且不同文件中的定义之间不会有任何冲突。由于您(可能)只使用这些值,而不将它们视为变量,因此拥有多个“副本”不会有任何影响——它们都不会被分配存储空间
在C语言中,
extern
是完全不同的,删除extern
不会产生任何真正的区别,因为默认情况下它们是extern
。在这种情况下,您确实需要在一个地方初始化变量,并在标头中对外声明它们。或者,可以在默认情况下添加C++时将添加的<代码>静态< /代码>存储类,如果从头中删除Jacob
extern
意味着变量的“真实”定义在别处,编译器应该相信在链接时事情会连接起来。将定义与extern
内联是一件很奇怪的事情,这正是你的程序所需要的。如果您想让它们成为extern
,只需在程序中的其他位置精确地定义它们一次。如果您想在头文件中定义常量,请使用static const
。如果您使用extern
,链接器抱怨多个定义是正确的,因为如果您指定一个值,每个包含源文件的文件都将为变量提供内存。看起来头文件被多次包含。您需要添加防护装置
在每个头文件的顶部,您应该有如下内容:
#ifndef MY_HEADER_FILE_NAME_H
#define MY_HEADER_FILE_NAME_H
...
// at end of file
#endif
如果您使用的是g++或MSVC,则只需添加:
#pragma once
在每个头文件的顶部,但这不是100%可移植的
此外,您不应该在头文件中定义常量,只声明它们:
// In header file
extern const int my_const;
// In one source file
const int my_const = 123;
在报头中声明全局常量会导致每个编译单元(包括此hader)都有自己的定义和同名的全局定义。 那么链接器不喜欢这样 若你们真的需要这些在头文件中,那个么你们可能应该把它们声明为静态的 问题在于您在头文件中定义了具有外部链接的对象。可以预料的是,一旦您将该头文件包含到多个翻译单元中,您将获得具有外部链接的同一对象的多个定义,这是一个错误 正确的方法取决于你的意图
静态的
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++ >代码>静态<代码>是可选的(因为C++中的代码> const 对象默认有内部链接)
extern
且不包含初始值设定项
一个实现文件中的定义应如下所示
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
(如果上述声明位于同一翻译单元中的定义之前,则定义中的显式extern
是可选的)&PI
将计算到每个翻译单元中的不同地址
第二种方法创建真正的全局常量,即整个程序共享的唯一常量对象。例如,&PI
将计算到每个翻译单元中的相同地址。但在这种情况下,编译器只能在一个且只有一个翻译单元中看到实际值,这可能会妨碍优化
从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;
在本例中,您将获得一个命名常量对象,其初始值设定项值在所有转换单元中都可见。同时,对象具有外部链接,即它具有全局地址标识(&PI
在所有转换单元中都是相同的)
当然,这样的一些东西对于某些异国的目的可能是必要的(C++中的大多数用例都调用第一个变体),但是特性是存在的。
< P>问题是,你正在初始化变量。template <typename Dummy = int>
struct C {
static const double Pi;
};
template <typename Dummy = int>
const double C<Dummy>::Pi = 3.14159;
static const uint64 GameTexSignature = 0x0a1a0a0d58455489;
static constexpr uint64 GameTexSignature = 0x0a1a0a0d58455489;