为什么“int i”有多个定义?

时间:2016-07-15 11:03:13

标签: c++ linker-errors header-files

我有两个文件如下:

Test1.h

#ifndef TEST_H
#define TEST_H

int i = 10;

#endif

测试2.cpp

#include <iostream>

#include "Test1.h"

int main()
{
    std::cout << i << std::endl;
}

我知道我可以在Test1.h中使用 extern const 解决此问题。

但我的问题是“我不理解错误”。

  

错误LNK2005:已在Test1.obj中定义了“int i”(?i @@ 3HA)   错误LNK1169:找到一个或多个多重定义的符号

int i如何有多个定义?

  1. 头文件包含警卫。
  2. 当我包含头文件时,它应该意味着所有内容都会被复制到Test2.cpp中,它应该成为:
  3. 测试2.cpp

    #include <iostream>
    
    int i = 10
    
    int main()
    {
        std::cout << i << std::endl;
    }
    

    在包含所有内容之后,头文件应该变得无关紧要。

    我的另一个问题是,如果我在头文件中使用int i声明extern并将其包含在.cpp中,那么它是否是外部链接的示例?因为通常我在here中看到了两个.c.cpp之间的外部链接,但是如果您明确包含该文件,它仍被视为i具有外部链接吗?

5 个答案:

答案 0 :(得分:2)

每个编译单元(.cpp文件)单独生成一组符号,然后由链接器链接在一起。

头文件“成为”它所包含的编译单元的一部分,它编译为目标文件(Windows中的.obj,Unix系统中的.o)

因此,就像您在每个编译单元中定义了一个全局“i”。 正确的解决方案(如您所知,如果必须具有全局)是在标头中将其声明为“extern”,然后让一个编译单元实际定义它。

包含防护仅防止在同一个编译单元中包含两次相同的标头,如果我包含,则会发生这种情况,其中一个包括另一个。

答案 1 :(得分:1)

您可能正在尝试从两个翻译单元创建可执行文件。

您的错误显示该对象已在Test1.obj中定义。可能你的程序是Test1.obj + Test2.obj,这两个文件包含相同的定义,它有外部链接。

答案 2 :(得分:1)

  

我怎么能有多个定义?

具有定义的文件包含在多个翻译单元(cpp文件)中。一个单元被编译到目标文件Test1.obj中。其他单位的来源显示在您的答案中(Test2.cpp)。当您尝试将目标文件链接在一起时,会显示错误。

  
      
  1. 头文件包含警卫。
  2.   

这可以防止在单个翻译单元中重复文件的内容。单独的单位没有区别。

  

我的另一个问题是,如果我在头文件中使用extern声明int i并将其包含在.cpp中,那么它是否是外部链接的一个例子?

extern明确表示外部链接。但即使没有extern,在命名空间范围内声明的变量默认也有隐式外部链接(有例外)。这种情况的不同之处在于extern变量声明不是定义,除非有初始化器。

  

我可以在不包含头文件的情况下实现外部链接,即通过在一个.cpp中创建一个变量extern并在另一个中定义它来获取两个.cpp文件,并且链接器找到它的定义。但是,如果我有一个带有extern变量的头文件并将其包含在其他.cpp中这会算作外部链接吗?

外部声明如何在cpp文件中结束并不重要。无论它是否包含在标题中,它都声明了一个带有外部链接的变量。

答案 3 :(得分:0)

您的项目中还有其他 Test1.cpp 还包含 Test1.h 吗?

如果没有,您是否对编译器进行了任何配置,以便它还将 .h 文件构建到目标文件中?

原因可以是上述两个问题之一的答案。

答案 4 :(得分:-1)

  

当我包含头文件时,它应该意味着所有内容都会在Test2.cpp中被复制,它应该变成:

是的,然后你在Test1.cpp中做了同样的事情(你没有告诉我们)。

因此,有多个定义。