2016-06-01 16 views
0

Ich schreibe ein C++ - Programm, bei dem jede Datei einen eigenen Satz globaler Variablendeklarationen hat. Die meisten dieser Dateien verwenden globale Variablen, die in den anderen Dateien mit extern definiert wurden.Mehrere Definitionen Fehler in C++

Hier ist ein Beispiel ähnlich wie mein Programm:

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; 
} 

Wenn ich diesen Code in Visual Studio erstellen (Windows), alles läuft gut und die Ausgabe ist korrekt. Aber wenn ich versuche, mit g ++ auf Linux zu bauen erhalte ich folgende Fehlermeldung:

g++ -o Testing Testing.o Other_File.o Other_File.o:(.bss+0x0): multiple definition of var3' Testing.o:(.bss+0x0): first defined here Other_File.o:(.bss+0x4): multiple definition of var4' Testing.o:(.bss+0x4): first defined here Other_File.o: In function otherFunction()': Other_File.cpp:(.text+0x0): multiple definition of otherFunction()' Testing.o:Testing.cpp:(.text+0x0): first defined here collect2: ld returned 1 exit status make: *** [Testing] Error 1

Ist das, weil ich „darunter“ die andere Datei in meiner Haupt-Datei?

Wenn nicht, was ist das Problem mit meinem Code?

Edit: Dies ist der Inhalt meiner Makefile für g ++:

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 
+5

Per Konvention sollte man nie eine cpp-Datei in eine andere cpp-Datei aufnehmen. – NathanOliver

+4

Welche Befehlszeile geben Sie an g ++ weiter? – Brian

+3

Ja, durch Einschließen der CPP-Datei endet die Definition zweimal - in der ursprünglichen cpp-Datei und in der Datei, die sie enthält (ich nehme an, Sie kompilieren auch die enthaltene cpp-Datei unabhängig voneinander). ** Thou SHANT enthalten CPP-Dateien **. – SergeyA

Antwort

3

nicht #include eine Quelldatei in einer anderen Quelldatei durchführt. Es gibt Zeiten und Orte, an denen das in Ordnung ist, aber nur in weniger als 0,001% aller Programme ist das nötig.

Was sollten Sie tun, ist eine Header-Datei erstellen, die Erklärungen der Dinge enthält alle benötigten Komponenten in beiden Quelldateien.

Dann würde der Code wie folgt aussehen:

  1. main.cpp Quelldatei

    #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 Quelldatei, so wie du es jetzt

  3. other_file.h Header-Datei haben, ein neue Datei

    #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(); 
    

Beide Quelldateien dann kompiliert getrennt werden würde und miteinander verknüpft die endgültige ausführbare Datei zu bilden. Diese Verknüpfung Schritt ist, wo Ihr Build fehlschlägt. Es wird bemerken, dass die in other_source.cpp definierten Variablen in der Objektdatei definiert sind, die aus dieser Quelldatei erstellt wurde, aber da Sie sie in die Quelldatei main.cpp einfügen, wird auch die aus dieser Quelldatei erstellte Objektdatei verwendet.

Deshalb müssen Sie über translation units lernen, was der Compiler tatsächlich sieht. Eine C++ - Quelldatei geht durch viele phases of translation, von denen jeder seinen eigenen speziellen Teil tut.Grob eine Übersetzungseinheit ist eine einzelne Quelldatei mit allen Kopfzeilen enthalten. Dies ist auch ein guter Grund zu lernen, was die preprocessor #include directive tut. Es fügt im Grunde genommen die enthaltene Datei in die Quelldatei ein, die gerade vorverarbeitet wird. Wo die #include Direktive war, nach der Vorverarbeitung wird es der Inhalt der enthaltenen Datei sein, und das ist, was der Compiler sehen wird.

+0

'other_file.cpp' sollte nicht' extern int var1; extern int var2; '- sie sollten auch in eine gemeinsame Headerdatei gehen (sei es' other_file.h' oder eine andere) –

+0

Aus Neugier, wann würde man eine Quelldatei einbinden (hier nach Quelldatei meine ich etwas, in das kompiliert wird) es ist eine eigene Objektdatei) – SergeyA

+0

@SergeyA Ich habe es in einem einfachen RTOS-Code mit direktem Direkt-zu-Hardware-Zugriff gesehen, aber dann wird die enthaltene Quelldatei nicht in eine Objektdatei kompiliert, die verlinkt ist. –

0

Eine umfassen effektiv fügt die enthaltene Datei in die einschließlich Datei, bevor der Compiler arbeiten beginnt, so wie das aussieht für den Compiler ist:

#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); 
} 

An sich kein Problem ist. Es sieht witzig aus, aber es ist kein Problem. Es gibt keine doppelten Variablen.

teilt dem Compiler mit, dass woanders existiert var1. Es wird später gefunden und verlinkt. Fortfahren. Der Linker wird sich beschweren, wenn Sie gelogen haben. In diesem Fall ist es ungefähr 10 Zeilen abwärts.

Das Problem tritt auf, wenn Other_File.cpp kompiliert und mit Main.cpp verknüpft ist. Der Linker findet eine vollständige Definition von var3 und var4 in beide main.o und Other_File.o

Sie Other_File.cpp aus dem Build ausschließen kann, wahrscheinlich, was Visual Studio für Sie getan haben, und alles wird gut, außer für eine ernsthafte Verstoß gegen Konvention: Niemals eine .cpp-Datei einfügen.

Warum? Weil cpp-Dateien per Konvention Dinge definieren und real machen. Sie können eine .h-Datei genauso verpfuschen, indem Sie eine Variable oder Funktion in der Kopfzeile definieren. zB:

#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_ */ 

Jeder, der jetzt umfasst badheader.h hat eine Variable mit dem Namen fubar, ob sie es wollen oder nicht, und wenn der Linker kommt das Programm zusammenzustellen, das fubar die wirkliche fubar ist? Alle von ihnen. Hoppla. Der schlechte Linker kann nur einen Fehler ausspucken und darauf warten, dass Sie die Mehrdeutigkeit beheben. Am Ende des Tages können Sie #include alles. Es wird nicht kompiliert, aber Sie könnten ein Word-Dokument einschließen. Sie können sogar kleine Tricks wie

int array[] = 
{ 
#include "filtercoefs.h" 
}; 

durchführen, wo array.h einfach ist

1,2,3,4,5 

Nützlich, wenn Sie so etwas wie Matlab spuckt Filterkoeffizienten haben, sondern auf die Konvention lieber kleben Verwirrung zu verhindern, unter Ihren Kollegen Programmierer.

Wie auch immer, C++ lässt Sie alle möglichen Dinge tun. Die meisten von ihnen denken besser ein paar Mal darüber nach, bevor sie es tun.