include, bitte mal richtig



  • Ich habe mich in die include-Direktive in zahlreichen Tutorials eingelesen. Dort traf ich u.a. auf Formulierungen wie "include Datei wird eingebunden, als ob ihr tatsächlicher Inhalt an dierser Stelle stände". Gut, aber klappt bei mir in der Praxis nicht, habe ich etwas falsch verstanden? Beispiel:

    main.cpp

    #include <iostream>
    #include "etwas.c"
    
    using namespace std;
    
    int main()
    {
        cout << sonstwas() << endl;
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Die eingebundene Datei "etwas.c"

    int sonstwas(int i = 0)
    {return (i + 1);}
    

    mein Compiler meckert: "multiple definition of 'sonstwas(int)'"??
    (Wenn die include-Datei keine Endung hat, dann überdies einen anderen Fehler.)
    Habs auch schon mit bedingter Compilierung, hier "#ifdef..." oder mit namspaces versucht, kein Unterschied.

    Wer kennt sich mit include Direktiven aus, besser, wo kann ich was darüber nachlesen, was über die gewöhnlichen Tutorials hinaus geht und meine Fragen beantwortet, oder ist der Fehler ganz anderer Natur (Programmiere mit der DevC++ IDE)?



  • Naja ... mach es so:
    main.cpp

    #include <iostream>
    #include ".\func.h" // Bei C inkludiert man für gewöhnlich nen Header ^^
    
    int main()
    {
        unsigned short value = 1;
        std::cout << "\"value\" betraegt: " << value << std::endl;
        raise_value(value);
        std::cout << "Nach der Funktion betraegt \"value\": " << value << std::endl;
    
        return 0;
    }
    

    func.h

    #if !defined(_FUNC_H__INCLUDED) // Hier nicht unbedingt nötig da die Datei ja eh nur einmal eingebunden wird. Les dir am besten mal etwas zu Includeguards durch ...
    #define _FUNC_H__INCLUDED
    
    #pragma once
    
    void raise_value(unsigned short&);
    
    #endif // _FUNC_H__INCLUDED
    

    func.cpp

    #include ".\func.h"
    
    void raise_value(unsigned short& value)
    {
        ++value;
    }
    


  • Danke, allerdings versteh ich nicht so ganz, warum der Compiler die Definition der Funktion "raise_value" kennt, obwohl die .cpp Datei weder direkt noch indirekt eingebunden wurde, anscheinend versteh ich das System komplett falsch.

    Und Danke für den Tipp mit #pragma once, wusste ich bisher noch nicht.



  • raise... wird dem Compiler doch in func.h bekannt gemacht.



  • Die Definition kennt der Compiler nur anhand der Headerdatei nicht. Dafür muss schon die cpp-Datei (wie Du so schön sagst direkt oder indirekt) eingebunden werden. Aber die Deklaration (im Header) muss in anderen cpp-Dateien bekannt sein in denen Du die Funktion nutzen möchtest.



  • OK, aber wie weiß der Compiler, dass er ausgerechnet diese .cpp Datei hier einbinden muss, eine include Direktive für die .cpp Datei kann ich im Beispiel nicht finden (,obwohl es nichtsdestotroz funktioniert).



  • Das weiss er, weil für die betreffende .cpp-Datei ein Compile-Kommando ausgeführt und die resultierende Objektdatei dann beim Aufruf des Linkers zusätzlich zu der des Hauptprogramms angegeben wurde. Bei gängigen IDEs wird das häufig dadurch ausgelöst, dass die betreffende .cpp-Datei "zum Projekt hinzugefügt" wird.



  • Ich versuche es noch einmal anhand deines ersten Beispiels zusammenzufassen.

    Dein Projekt/Programm besteht aus zwei Implementierungsdateien die getrennt voneinander übersetzt werden
    main.cpp und etwas.cpp

    3 Fälle:
    1.

    #include <iostream>
    
    int main()
    {
        sonstwas();
        return 0;
    }
    

    Der Compiler stößt bei der Übersetzung von main.cpp auf den Funktionsauruf sonstwas(). Er kennt diese Funktion nicht und beschwert sich. Main.cpp kann nicht übersetzt werden.

    #include <iostream>
    #include "etwas.cpp"
    
    int main()
    {
        sonstwas();
        return 0;
    }
    

    Durch #include "etwas.cpp" ist es - wie du korrekt sagst - als ob der tatsächliche Inhalt von etwas.cpp zu Beginn von main.cpp stünde. Der Compiler kennt damit die Funktion sonstwas(), allerdings ist sie durch das include zum einen in main.cpp definiert als auch in etwas.cpp selbst und damit zweimal in deinem Programm, was der "One definition rule" widerspricht. (Würdest du etwas.cpp vom Build ausschließen, würde das auf diese Weise funktionieren, ist allerdings (i.d.R.) nicht empfehlenswert).

    #include <iostream>
    #include "etwas.h"
    
    int main()
    {
        sonstwas();
        return 0;
    }
    

    Durch die Deklaration (nicht Definition) von sonstwas() in der Header-Datei etwas.h und deren include in main.cpp, weiß der Compiler beim Übersetzen von main.cpp, dass diese Funktion "irgendwo" existiert, er weiß, welche Parameter sie nimmt und was sie zurückgibt und kann damit main.cpp übersetzen (etwas.cpp kann ebenfalls übersetzt werden). Der Linker bindet schließlich die übersetzten Dateien zum eigentlichen Programm zusammen.

    (Falls ich irgedwo Blödsinn erzählt haben sollte, korrigiert mich bitte ;)).



  • (D)Evil schrieb:

    Naja ... mach es so:
    main.cpp

    #include <iostream>
    #include ".\func.h" // Bei C inkludiert man für gewöhnlich nen Header ^^
    
    int main()
    {
        //...
    }
    

    #include "func.h" ist korrekt und portabler. Nicht alle Betriebssysteme benutzen \ als Trennzeichen.

    (D)Evil schrieb:

    func.h

    #if !defined(_FUNC_H__INCLUDED) // Hier nicht unbedingt nötig da die Datei ja eh nur einmal eingebunden wird. Les dir am besten mal etwas zu Includeguards durch ...
    #define _FUNC_H__INCLUDED
    
    #pragma once
    
    void raise_value(unsigned short&);
    
    #endif // _FUNC_H__INCLUDED
    

    Was mit einem _ beginnt, ist für den Compiler reserviert. Nicht, dass es irgeneinen Compiler stört, dass du einen _ am Anfang benutzt (außer du legst es drauf an oder hast Pech). Andererseits ist es auch vollkommen unnötig, genau wie das Pragma. Einfache Includeguards reichen:

    #ifndef PROJECT_MODULE_INCLUDED
    #define PROJECT_MODULE_INCLUDED
    //PROJECT_MODULE_INCLUDED sollte natürlich für jeden Header anders und sinnvoll sein
    //...
    #endif //PROJECT_MODULE_INCLUDED
    


  • Naja davon mal abgesehen das ich ein #if und ein #endif vergessen hab, ist ein #pragma once eig. vorteilhafter als ein normaler Inkludeguard. Diese Diskussion fand aber schon einmal in diesem Forum statt.

    Das ich ein _ davor gemacht hab, liegt nur daran, das es mir besser gefiel, aber du hast recht es war nicht die beste Idee. Nunja.



  • Danke nochmal, für die vielen Antworten, also weiß der Compiler, sobald eine Funktion deklariert ist, dass es sie gibt und sucht danach (nach irgendwelchen Regeln wahrscheinlich, denn er durchsucht bestimmt nicht die gesammte HD) und bindet sie ein, falls schonmal eingebunden durch include, ist sie natürlich mehr als einmal definiert und das ist ein Fehler nach der "One definition rule...". OK, damit kann ich was anfangen, danke nochmal :).



  • benschni schrieb:

    Danke nochmal, für die vielen Antworten, also weiß der Compiler, sobald eine Funktion deklariert ist, dass es sie gibt und sucht danach (nach irgendwelchen Regeln wahrscheinlich, denn er durchsucht bestimmt nicht die gesammte HD)

    Genau richtig erkannt - und diese Regel lautet in etwa so, daß du angeben mußt, wo er zu suchen hat (wenn du aus der Eingabeaufforderung compilierst, mußt du die Namen aller beteiligten Quell-Dateien und LIB's mit angeben (oder ins Makefile eintragen), IDE-Compiler wie der MSVC erledigen das automatisch, indem sie alle Quelldateien deines Projekts und alle von dir angegebenen LIBs mitnehmen.



  • Klasse, danke!!


Log in to reply