在头文件中声明和定义且仅在其 cpp 文件中使用的变量的多重定义错误

Multiple definition error on variable that is declared and defined in header file and used only in its cpp file

我正在将为一个芯片编译的代码移动到另一个芯片上。

出现的一个问题是大量的多重定义错误。其中一些似乎是由于第一个芯片的 linker 让我懒得在多个源文件中使用变量 extern 时声明变量。我以前根本没有使用 extern(在 [=39= 中声明和定义一个变量,在 something.cpp 和其他包含 something.h 的源文件中使用它)并且编译并 link非常好。

我已经很好地解决了这些问题,我相信:现在我共享的变量具有这种模式:

Something.h

extern int foo;

Something.cpp

int foo = 0;

//using foo to do stuff

Main.cpp

#include "Something.h"

//using foo to do stuff

一切顺利。

这里有一点我不明白,似乎无法在这里或 Google 上找到任何答案。我注意到相同的多重定义错误是由在 Something.h 中声明和定义并在 Something.cpp.

中仅使用 的变量引起的

Something.h 有一个包含保护,所以我不认为这是因为 Something.h 在我的程序中的某个地方被多次包含。

如果我将它声明为 extern 并在 cpp 文件中定义它,错误就会消失,但这对我来说是错误的。我相信 extern 不需要 link Something.h 和 Something.cpp 之间的变量。

任何建议将不胜感激,我真的很想了解我在这里遗漏了什么。

(顺便说一下,我正在使用 Arduino IDE 为 ESP32 编译。)

The error goes away if I declare it as extern and define it in the cpp file,

问题是,即使包含保护等,变量也会在每个编译单元中创建一次 - 但由于它是全局的,所以它指向同一个变量。

要解决这个问题,您需要立即创建它。命名空间

Something.h

namespace {
  int foo = 0;
}

或者,使用静态关键字

Something.h

 static int foo = 0;

两者都会在每个编译单元中创建不同的变量。

如果您在头文件中声明您的变量:

#ifndef GLOBAL_H
#define GLOBAL_H

int foo = 0;

#endif

在头文件或翻译单元的每个包含中,都会创建一个整数的新实例。正如你提到的,为了避免这种情况,你需要在头文件中将项目声明为"extern"并在实现文件中对其进行初始化:

// .h
extern int foo;

// .cpp
int foo = 0

更多的 C++ 方法可以是这样的:

#ifndef GLOBAL_H
#define GLOBAL_H

struct Global {
    static int foo;
};
#endif

并且在您的 cpp 文件中:

#include "variables.h"

int Global::foo = 0;

C++17 修复了内联变量的这个问题,所以你可以这样做:

#ifndef GLOBAL_H
#define GLOBAL_H

inline int foo = 0;

#endif

有关详细信息,请参阅

在 C++ 17 中,您可以通过内联变量解决此问题。内联变量避免了在头文件中定义的变量重复。头文件中定义的变量将被视为在 cpp 文件中初始化。它们不会被复制。所以可以直接包含代码。