【问题标题】:Header guards do not seem to work?头后卫似乎不起作用?
【发布时间】:2013-09-02 18:59:16
【问题描述】:

我在单独的标头中声明了一些常量变量(即 constant.h)。

我在 debug.cpp 中包含了 constant.h 以访问该变量。

我在 ma​​in.cpp 中包含 constant.hdebug.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

/-- debug.h --/

#ifndef DEBUG_H
#define DEBUG_H

#include <QString>

class Debug
{  
public:
    static void Log(QString Message);
};

#endif // DEBUG_H

/-- debug.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
}

/-- main.cpp --/

#include "constant.h"
#include "debug.h"

int main(int argc, char *argv[])
{
    Debug::Log("New application has been run");
}

【问题讨论】:

  • 我没有收到与您相同的链接器错误:我收到了multiple definition of 'APP_NAME'(不是'IF_DEBUG_ENABLED')。我还收到第二个错误:undefined reference to 'Debug::Log(QString)'.
  • 自从你开始学习以来,你有很多东西要学。至少有一段时间我会坚持使用单个源文件中的程序。少一件事让你绊倒。
  • 另一件事。没有像 C/C++ 这样的语言,只有 C 和 C++。你正在学习 C++。说 C/C++ 的人往往会被激怒。
  • 还有一件事,问得很好。包括回答它所需的一切。质量比我们通常在这个论坛上看到的要高得多。你会走得很远。

标签: c++ header-files


【解决方案1】:

C 和 C++ 有“编译单元”的概念,它本质上是“你告诉我编译的文件中的所有代码加上它包含的所有文件”。

C 编译的原始管道是首先运行“预处理器”以读取所有代码、处理宏和定义等,并将生成的代码输出到单个文件中(从内存中,.i中间文件)

foo.cpp

#include "foo1.h"
FOO {
    #include "foo2.h"
}

foo1.h

extern "C" int puts(const char*);
#define FOO int main()

foo2.h

puts("Hello, world\n");

使用g++ -Wall -E -o foo.i foo.cppg++ -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
}

这是一个编译单元。这些天来,这个过程被简化了,预处理器被内置到编译器本身中,但编译单元的概念仍然存在。

您的代码的问题在于您在头文件中定义 - 而不仅仅是声明 - IF_DEBUG_ENABLED,因此可能在多个编译单元中。当链接器尝试将已编译的单元组合成可执行文件时,它会找到同名变量的多个实例。链接器无法判断它们应该是同一个东西。

要创建在多个编译单元(源文件)之间可见的全局变量或函数,您需要一个标头声明/原型和一个源文件定义/实例。

标题

extern bool IF_DEBUG_ENABLED; // variable declaration.
extern void herp();           // function prototype, but
void herp();                  // the extern is optional for functions.

为了能够使用其中任何一个,您现在需要通过实现来备份它们。

源文件

bool IF_DEBUG_ENABLED = true;

这是,假设您希望它是一个运行时变量。您的另一个选择是使用#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

来源:

#if defined(IF_DEBUG_ENABLED)
   qDebug() << message;
#endif

此选项不允许您在运行时更改 IF_DEBUG_ENABLED,只有在编译时定义了 IF_DEBUG_ENABLED 时,“qDebug()

最后,不用#if ... #define ... #endif 保护方法,您可以在文件开头用一行替换所有三个:

常数.h:

#pragma once  //<<-- compiler implements a guard for you.

#include <QString>

class Debug
{  
public:
    static void Log(QString Message);
};

【讨论】:

  • 这样,当我尝试在我的应用程序的主(入口点)函数中为 extern 声明的变量赋值时,我会得到一个未定义的对“IF_DEBUG_ENABLED”的引用。
  • 好吧,事情正在编译,但我对在哪里初始化这些外部变量感到困惑?
  • 哟!我把东西建立起来并运行了!你的帮助我真的。清晰如镜! :P (y) 谢谢!
【解决方案2】:

您应该将定义放在 .cpp 文件中,而不是在标题中。在标题中你应该只放 declarationsextern const bool IF_DEBUG_ENABLED; 这将告诉任何代码#includeing 它存在一些名为IF_DEBUG_ENABLED 的全局变量。在 debug.cpp 中你应该把实际的定义放在里面。

守卫仅有助于防止您在单个编译单元中定义多次。但是你有两个编译单元:debug.cpp(加上头文件)和 main.cpp(加上头文件)。这意味着您在标头中有多个变量定义。


你还有一个问题:你实现了一个静态函数Log(),但你应该实现一个静态类方法Debug::Log()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-20
    • 2015-04-11
    • 2019-10-28
    • 2016-11-29
    • 2016-02-01
    • 2020-09-23
    • 2010-12-05
    • 2011-06-14
    相关资源
    最近更新 更多