【问题标题】:creating global variables causes linker error创建全局变量会导致链接器错误
【发布时间】:2024-01-21 05:47:01
【问题描述】:

我有一个 MFC 应用程序 AVT_testapp,在头文件 (AVT_testappDlg.h) 中,我试图在所有函数、类等之外创建一个变量,以使其成为全局变量。每当我尝试这样做时(比如我尝试int x = 7),我都会收到错误消息:

1>AVT_testappDlg.obj : error LNK2005: "int x" (?x@@3HA) already defined in 
    AVT_testapp.obj
1>..\..\bin\x64\Debug\AVT_testapp.exe : fatal error LNK1169: one or more 
    multiply defined symbols found

我在 google 上找到的所有内容都说“只需添加标头保护”。 AVT_testappDlg 有 6 个#include,每个都有标头保护。

在创建全局变量时还有什么可能导致这些错误?

编辑:这是我的头文件的开头,

#pragma once

#include "../../src/CoreUtils/nierr.h"
#include "..\..\src\CoreUtils\StringHelpers.h" //includes windows.h
#include "afxwin.h"
#include "afxcmn.h"
#include "IFrameObserver.h"
#include "c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\GdiPlusHeaders.h"
//#include <fstream>
//#include <windows.h>

int x = 7;

using namespace AVT::VmbAPI;


//////////////////////////////////////////////////////////////////////////
//////////  MyObserver class   ///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class MyObserver : public IFrameObserver
{
private:
    MyObserver( MyObserver& );

    MyObserver& operator=( const MyObserver& );    

public:

    VmbUchar_t* imageData;

            //...
            //...
            //...
            //...

//that's the end of the relevant stuff

【问题讨论】:

    标签: c++ mfc linker compiler-errors global-variables


    【解决方案1】:

    您不能在标题中的命名空间级别定义变量。一般来说,最好不要有全局变量,但如果需要,您应该在标头中仅提供 声明,并在单个 .cpp 中提供定义:

    //header
    extern int i;
    
    //cpp
    int i;
    

    您的代码问题与标头保护无关。标头保护确保标头在每个翻译单元中仅解析一次。缺少标头保护会导致 compiler 错误,其中编译器会看到,例如一个类,在预处理后在同一个翻译单元中定义了多次。在您的情况下,错误是链接器错误 LNK2005,这意味着在多个翻译单元中定义了相同的符号(在您的情况下,在每个翻译单元中都包含带有定义的标题)。

    【讨论】:

    • int i = 7; 更改为 extern int i; 并没有消除错误
    • @xcdemon05 您是否重建了所有受影响的 .cpp 文件?您是否遇到 same 错误?
    • 抱歉,我不小心删除了我在最后一条之后的评论,但是我修复了它
    【解决方案2】:

    如果全局变量不是const(*),你不能把它放在一个头文件中并包含在多个翻译单元中(即.cpp文件)。否则,您将在程序中对同一符号进行多个定义,从而违反 ODR一个定义规则,请参阅 C++11 标准的第 3.2 段) ,并且链接器会抱怨这一点。

    您应该在共享标头中使用 extern 修饰符来仅提供变量声明:

    extern int var;
    

    然后,在一个 .cpp 文件中,您可以为其提供定义:

    int var;
    

    (*) const 全局变量默认具有内部链接,因此每个翻译单元最终都会拥有它的私有副本,不会发生多重定义。

    【讨论】:

      【解决方案3】:

      如果你坚持要有一个全局变量,至少把它放在一个命名空间中以避免与其他模块发生冲突

      namespace globals
      {
        extern int x;
      }
      

      然后在 .cpp 文件中定义它。

      int globals::x = 0;
      

      它也更清楚地表明它是一个全局变量。

      【讨论】: