在头文件中声明和定义且仅在其 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 文件中初始化。它们不会被复制。所以可以直接包含代码。
我正在将为一个芯片编译的代码移动到另一个芯片上。
出现的一个问题是大量的多重定义错误。其中一些似乎是由于第一个芯片的 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 文件中初始化。它们不会被复制。所以可以直接包含代码。