C ++中有多个定义错误

时间:2016-06-01 20:43:41

标签: c++ compilation linkage

我正在编写一个C ++程序,其中每个文件都有自己的全局变量声明集。这些文件中的大多数都使用了使用extern在其他文件中定义的全局变量。

这是一个类似于我的程序的例子:

Main.cpp的

#include "stdafx.h"
#include <iostream>
#include "Other_File.cpp"

int var1;
int var2;

int main()
{
    var1 = 1;
    var2 = 2;
    otherFunction();
    var4 = 4; // From Other_File.cpp

    std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;

    return(0);
}

Other_File.cpp

extern int var1;
extern int var2;

int var3;
int var4;

void otherFunction()
{
     var3 = var1 + var2;
     var4 = 0;
}

当我在Visual Studio(Windows)中构建此代码时,一切运行正常,输出正确。但是当我尝试在Linux上使用g ++构建时,我收到以下错误:

  

g ++ -o Testing Testing.o Other_File.o Other_File.o :(。bss + 0x0):   var3' Testing.o:(.bss+0x0): first defined here Other_File.o:(.bss+0x4): multiple definition of var4'的多重定义   Testing.o :(。bss + 0x4):首先在这里定义Other_File.o:在函数中   otherFunction()': Other_File.cpp:(.text+0x0): multiple definition of otherFunction()'Testing.o:Testing.cpp :(。text + 0x0):首先定义   这里collect2:ld返回1退出状态make:*** [测试]错误1

这是因为我在主文件中“包含”了另一个文件吗?

如果不是我的代码有什么问题?

编辑:这是我的g ++ Makefile的内容:

Testing: Testing.o Other_File.o
    g++ -o Testing Testing.o Other_File.o

Testing.o: Testing.cpp
    g++ -c -std=c++0x Testing.cpp

Other_File.o: Other_File.cpp
    g++ -c -std=c++0x Other_File.cpp

clean:
    rm *.o Calculator

2 个答案:

答案 0 :(得分:3)

不要将#include源文件放入另一个源文件中。有时间和地点可以,但只有少于0.001%的所有程序才需要。

您应该做的是创建一个标头文件,其中包含两个源文件中所需内容的声明

然后你的代码看起来像这样:

  1. main.cpp源文件

    #include "stdafx.h"
    #include <iostream>
    #include "Other_File.h"  // Note inclusion of header file here
    
    int var1;
    int var2;
    
    int main()
    {
        var1 = 1;
        var2 = 2;
        otherFunction();
        var4 = 4; // From Other_File.cpp
    
        std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
    }
    
  2. other_file.cpp源文件,就像您现在拥有的那样

  3. other_file.h头文件,新文件

    #pragma once
    
    // Declare the variables, so the compiler knows they exist somewhere
    extern int var3;
    extern int var4;
    
    // Forward declaration of the function prototype
    void otherFunction();
    
  4. 然后将两个源文件分别编译并将链接一起形成最终的可执行文件。此链接步骤是您的构建失败的地方。它会注意到other_source.cpp中定义的变量是在从该源文件创建的目标文件中定义的,但是由于您将其包含在main.cpp源文件中,因此从该源文件创建的目标文件也是如此

    这就是你需要了解编译器实际看到的translation units的原因。 C ++源文件经历了许多phases of translation,每个文件都有自己的特殊部分。 翻译单元大致是一个包含所有标题的单个源文件。

    这也是了解preprocessor #include directive所做事情的一个很好的理由。它基本上将包含的文件插入到正在预处理的源文件中。在#include指令所在的位置,在预处理之后它将是包含文件的内容,这就是编译器将看到的内容。

答案 1 :(得分:0)

include在编译器开始工作之前有效地将包含的文件粘贴到包含文件中,因此编译器看起来像是:

#include "stdafx.h"
#include <iostream>
// #include "Other_File.cpp" sub in other file here
extern int var1;
extern int var2;

int var3;
int var4;

void otherFunction()
{
     var3 = var1 + var2;
     var4 = 0;
}


int var1;
int var2;

int main()
{
    var1 = 1;
    var2 = 2;
    otherFunction();
    var4 = 4; // From Other_File.cpp

    std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;

    return(0);
}

这本身并不是问题所在。看起来很滑稽,但这不是问题。没有重复的变量。

extern int var1;

告诉编译器其他地方存在var1。它将在以后找到并链接。继续。如果你说谎,链接器会抱怨。在这种情况下,大约有10行。

编译Other_File.cpp并与Main.cpp链接时出现问题。链接器在Main.o和Other_File.o中找到var3var4的完整定义

您可以从构建中排除Other_File.cpp,可能是Visual Studio为您所做的事情,除非严重违反约定,否则一切都会好:永远不要包含.cpp文件。

为什么呢?因为按照惯例,cpp文件定义东西并使它们真实。您可以通过在标头中定义变量或函数来严重破坏.h文件。例如:

#ifndef BADHEADER_H_
#define BADHEADER_H_


int fubar; // don't do this
/* do this instead:
extern int fubar;
and place int fubar; into the most logical cpp file
*/


#endif /* BADHEADER_H_ */

包含badheader.h的每个人现在都有一个名为fubar的变量,无论他们是否需要它,以及链接器何时出现组装程序,fubar是真正的fubar ?他们都是。哎呦。所有可怜的链接器都可以做出错误并等待你修复歧义。

在一天结束时,你可以#include任何事情。它不会编译,但您可以包含Word文档。你甚至可以执行像

这样的小动作
int array[] =
{
#include "filtercoefs.h"
};

其中array.h只是

1,2,3,4,5

当你有类似Matlab吐出滤波器系数的东西时很有用,但更喜欢坚持惯例以防止你的同伴之间的混淆。

无论如何,C ++可以让你做各种各样的事情。他们中的大多数人在做这些之前最好多想几次。

相关问题