【问题标题】:Header file containing 'const' included in multiple source files包含在多个源文件中的“const”的头文件
【发布时间】:2012-08-16 04:37:38
【问题描述】:

为什么包含const 定义并被多个源文件包含的头文件会导致multiple definition 的编译错误?

const_in_header_file.h

const int num = 5;
//int x; //Error. Multiple defintion if included from multiple source files.

const_in_header_file_func.cpp

#include <iostream>
#include "const_in_header_file.h"

using namespace std;

void func(void)
{
   cout << "num in func() = " << num << endl;
}

const_in_header_file_main.cpp

#include <iostream>
#include "const_in_header_file.h"

using namespace std;
extern void func(void);

int main()
{
   cout << "num in main() = " << num << endl;
   func();
}

【问题讨论】:

  • 你能准确地展示声明的样子,包括所有相关类型吗?
  • @GregHewgill 可能根本不需要 :)
  • 可能确实如此。显示实际代码总是有帮助的。
  • 您需要出示代码才能获得直接答案。在某些情况下和某些范围内,标头中的定义可能合法存在,并且可能对多个 TU 可见,但 C++ 在这方面存在大量变化。在 C++ 中,有多种方法可以解决此问题,但同样 - 这取决于类型和范围。
  • 对不起,我的错误。我的意思是does not。但由于网络中断,在答案涌入之前无法更新

标签: c++ constants


【解决方案1】:

在 C++ 中,全局 const 是内部链接。将头文件与 cpp 文件合并后(头文件将“插入”到 #include 所在的 cpp 文件中),每个编译单元将被编译为目标文件,然后链接在一起。那些是内部链接的函数和变量不会被链接器看到,这意味着你的 const global 在这个阶段不会被看到。即使您在不同的目标文件中有两个或多个 const,它们也只是隐藏的。 只有那些具有外部链接函数和变量的链接器才会尝试将声明与定义“组装”起来。 例如: 如果你有 extern int a; 在一个编译单元中(插入 .h 的 cpp); 链接器将搜索它的定义: int a;(没有外部关键字)。 如果找到两个,就会出现重定义错误。

对于常量,它们只是对链接器隐藏。

【讨论】:

    【解决方案2】:

    因为如果它真的是一个定义而不是一个声明,那么编译器会在它一次又一次遇到定义 - 然后链接器不知道如何处理生成的目标代码文件中具有相同名称的多个符号。

    【讨论】:

    • 猜测:因为const变量默认有内部链接?
    • @CharlesBailey 谢谢! (但我猜你没有投反对票。)但是,这里不应该是这种情况 - 多重定义错误是由具有外部链接的重复符号引起的。或者我错过了一些关于静态链接的东西。或者 OP 的编译器的错误。
    • A compile 错误“多个定义”表示对象已在翻译单元中多次定义,因此对象的链接无关紧要。
    • @CharlesBailey 真的吗?然后尝试将两个包含相同函数的目标文件链接在一起。
    • 我不明白您的上一条评论与我的评论有何关联。如果我的翻译单元编译失败,我一开始就没有目标文件可以链接,这就是为什么我说链接无关紧要。
    【解决方案3】:

    可能是因为您编写了头文件...但未能包含“header guards"”。

    缺少“标头保护”会导致编译错误。另一种可能是您没有使用“extern”。这会导致链接错误。

    例如:

    #ifndef MY_HEADER_H
    #define MY_HEADER_H
    
    extern int myglobal;
    
    #endif
    

    请看上面两个链接。如果添加保护和/或使用“extern”不能解决问题,请发布失败的代码的 sn-p。

    【讨论】:

    • 正如您所说:“缺少标头保护会导致 compiler 错误...” - 但不是 linker 错误,如OP 写道(因为如果编译出错,链接甚至不会开始)。
    猜你喜欢
    • 1970-01-01
    • 2012-04-14
    • 2020-03-11
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    相关资源
    最近更新 更多