Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 常量变量在标头中不起作用_C++_C_Visual Studio_Visual Studio 2008_Visual C++ - Fatal编程技术网

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++时将添加的<代码>静态< /代码>存储类,如果从头中删除 ExtNe>代码> .< /p> ,您需要在标题中声明这些内容,然后在代码文件中定义它们。如果您没有在任何地方声明它们,那么当链接器尝试将声明绑定到实际定义时,就会出现链接器错误。您还可以使用#ifdef语句在标题中包含一个定义

确保它们在每个需要它们的人都包含的标题中声明,并确保它们只定义一次


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)都有自己的定义和同名的全局定义。 那么链接器不喜欢这样

若你们真的需要这些在头文件中,那个么你们可能应该把它们声明为静态的

问题在于您在头文件中定义了具有外部链接的对象。可以预料的是,一旦您将该头文件包含到多个翻译单元中,您将获得具有外部链接的同一对象的多个定义,这是一个错误

正确的方法取决于你的意图

  • 您可以将定义放入头文件中,但请确保它们具有内部链接

    在C语言中,需要显式的
    静态的

    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;