num*_*l25 55 c c++ visual-studio-2008 visual-studio 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;
Run Code Online (Sandbox Code Playgroud)
我收到以下错误
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
Run Code Online (Sandbox Code Playgroud)
但是如果我从标题中删除这些常量并将它们放在包含这样的标题的文档中......
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
Run Code Online (Sandbox Code Playgroud)
有用
有没有人有想法我可能做错了什么?
谢谢
AnT*_*AnT 130
问题是您在头文件中定义了具有外部链接的对象.预计,一旦将该头文件包含到多个翻译单元中,您将获得具有外部链接的同一对象的多个定义,这是一个错误.
正确的方法取决于你的意图.
您可以将定义放入头文件中,但要确保它们具有内部链接.
在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;
Run Code Online (Sandbox Code Playgroud)
在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;
Run Code Online (Sandbox Code Playgroud)或者,您可以将非定义声明放入头文件中,并将定义放入一个(并且只有一个)实现文件中
头文件中的声明必须包含显式extern
和无初始化程序
extern const double PI;
extern const double PI_under_180;
extern const double PI_over_180;
Run Code Online (Sandbox Code Playgroud)
一个实现文件中的定义应如下所示
const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;
Run Code Online (Sandbox Code Playgroud)
(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;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将获得一个命名常量对象,其初始化值在所有翻译单元中都可见.同时,对象具有外部链接,即它具有全局地址标识(&PI
在所有翻译单元中都是相同的).
当然,类似的东西可能只是一些奇特的目的所必需的(C++中的大多数用例都需要第一个变体),但功能就在那里.
extern
意味着变量的"真实"定义在其他地方,并且编译器应该相信事物会在链接时挂钩.将定义内联到该内容extern
是很奇怪的,并且正在修改您的程序.如果你想拥有它们extern
,只需在程序的其他地方准确定义它们.
extern
他们的存储类几乎肯定是你所看到的问题的原因.如果你删除它,代码可能会很好(至少在这方面).
编辑:我刚刚注意到你已将其标记为C和C++.在这方面,C和C++实际上是完全不同的(但从错误消息中,你显然编译为C++,而不是C).在C++中,您要删除extern
,因为(默认情况下)const
变量具有static
存储类.这意味着每个源文件(翻译单元)将获得自己的变量"副本",并且不同文件中的定义之间不会有任何冲突.由于您(可能)只使用这些值,而不是将它们视为变量,因此拥有多个"副本"不会对任何内容产生任何影响 - 它们都不会被分配存储空间.
在C中,extern
是相当不同的,删除extern
不会产生任何真正的区别,因为它们将是extern
默认的.在这种情况下,您确实需要在一个位置初始化变量,并在标题中将它们声明为extern.或者,您可以添加static
C++将在/ extern
从标头中删除时默认添加的存储类.