我在单独的标头中声明了一些常量变量(即constant.h)。
我将constant.h 包含在我的debug.cpp中以访问该变量。
我在main.cpp中包含constant.h、debug.h来访问变量。
当我编译时,它显示错误**multiple definition** of **IF_DEBUG_ENABLED**。
请告诉我我实际上做错了什么。另外,请注意,这是我第一次使用c/c++应用程序的第一天。我什至在学校里都没读过。
我的代码源码如下:如
/ -- 常量.h -- /
#ifndef CONSTANT_H
#define CONSTANT_H
const char* APP_NAME = "ymcmcb";
const bool IF_DEBUG_ENABLED = true;
#endif // CONSTANT_H
Run Code Online (Sandbox Code Playgroud)
/ -- 调试.h -- /
#ifndef DEBUG_H
#define DEBUG_H
#include <QString>
class Debug
{
public:
static void Log(QString Message);
};
#endif // DEBUG_H
Run Code Online (Sandbox Code Playgroud)
/ -- 调试.cpp -- /
#include "constant.h"
#include "debug.h"
#include "QDebug"
static void Log(QString Message)
{
if (IF_DEBUG_ENABLED)
qDebug() << Message; //It says problem is here
}
Run Code Online (Sandbox Code Playgroud)
/ -- main.cpp -- /
#include "constant.h"
#include "debug.h"
int main(int argc, char *argv[])
{
Debug::Log("New application has been run");
}
Run Code Online (Sandbox Code Playgroud)
C 和 C++ 有“编译单元”的概念,本质上是“你告诉我要编译的文件中的所有代码加上它包含的所有文件”。
C 编译的原始管道是首先运行“预处理器”来读入所有代码,处理宏和定义等,并将结果代码输出到单个文件中(从内存中,一个 .i 文件用于中间) )
foo.cpp
#include "foo1.h"
FOO {
#include "foo2.h"
}
Run Code Online (Sandbox Code Playgroud)
foo1.h
extern "C" int puts(const char*);
#define FOO int main()
Run Code Online (Sandbox Code Playgroud)
foo2.h
puts("Hello, world\n");
Run Code Online (Sandbox Code Playgroud)
使用g++ -Wall -E -o foo.i foo.cpp和进行编译g++ -Wall -o foo.exe foo.i
该foo.i文件如下所示:
# 1 "foo.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "foo.cpp"
# 1 "foo1.h" 1
extern "C" int puts(const char*);
# 2 "foo.cpp" 2
int main() {
# 1 "foo2.h" 1
puts("Hello, world!\n");
# 5 "foo.cpp" 2
}
Run Code Online (Sandbox Code Playgroud)
这是一个编译单元。如今,该过程已得到简化,预处理器内置于编译器本身中,但编译单元的概念仍然保留。
您的代码的问题在于您是IF_DEBUG_ENABLED在头文件中定义(而不仅仅是声明),因此可能在多个编译单元中定义。当链接器尝试将编译的单元组合成可执行文件时,它会找到同名变量的多个实例。链接器无法判断它们应该是同一件事。
要创建在多个编译单元(源文件)之间可见的全局变量或函数,您需要标头声明/原型和源文件定义/实例。
标头
extern bool IF_DEBUG_ENABLED; // variable declaration.
extern void herp(); // function prototype, but
void herp(); // the extern is optional for functions.
Run Code Online (Sandbox Code Playgroud)
为了能够使用其中任何一个,您现在需要通过实现来支持它们。
源文件
bool IF_DEBUG_ENABLED = true;
Run Code Online (Sandbox Code Playgroud)
这是假设您希望它是一个运行时变量。您的另一个选择是使用 #define,就像您使用的防护一样:
常数.h
#ifndef CONSTANT_H // poor choice, there may be a CONSTANT_H somewhere else.
#define CONSTANT_H 1
...
#define IF_DEBUG_ENABLED // comment out to disable
#endif
Run Code Online (Sandbox Code Playgroud)
来源:
#if defined(IF_DEBUG_ENABLED)
qDebug() << message;
#endif
Run Code Online (Sandbox Code Playgroud)
此选项不允许您在运行时更改 IF_DEBUG_ENABLED,只有在编译时定义了 IF_DEBUG_ENABLED 时,“qDebug() << message”代码才会写入可执行文件。
最后,您可以在文件开头用一行替换所有三个,而不是使用 #if ... #define ... #endif 保护方法:
常量.h:
#pragma once //<<-- compiler implements a guard for you.
#include <QString>
class Debug
{
public:
static void Log(QString Message);
};
Run Code Online (Sandbox Code Playgroud)