Präprozessor und #include ignorieren



  • Hallo ihr Lieben,

    ich habe folgendes Problem:

    Ich habe z.B. eine Klasse foo

    #ifndef FOO_H_
    #define FOO_H_
    
    #include <c++ Stuff>
    
    #include <boost library path>
    
    #endif
    
    class FOO {
      /* declare something
         implementeation in foo.cpp */
    };
    

    Und dann natürlich eine main

    #include "foo.h"
    
    int main() {
      /* something */
    
      return 0;
    }
    

    Jetzt habe ich folgendes Problem bei Kompilieren:

    Ich kompiliere zunächst zunächst foo.cpp unter Angabe des Pfades zu z.B. Boost mittels -I/usr/local/boost_1_55_0/

    Jetzt will ich main.cpp kompilieren natürlich ohne Angabe des Pfades, denn alles was mit boost zu tun hat, wurde bereits bei der Kompilierung von foo.cpp abgehandelt.

    Und nun merke ich, dass ich diese include guards noch nicht richtig verstanden habe, denn der Kompiler meckert bei der Kompilierung von main.cpp , dass er z.B. Methoden aus Boost nicht findet (weil ich den Pfad nicht angebe, klar).

    Ich dachte das mit den include guards funktioniert so:

    1. foo.cpp wird kompiliert. Dabei existiert noch kein FOO_H_ , d.h. zum Einen wird dieses Symbol (diese Variable?) angelegt und anschließend alles includiert.
    2. main.cpp wird kompiliert. Es fügt foo.h und check, ob FOO_H_ bereits existiert - jap, tut es. Also sollte das nachfolgende doch nicht mehr includiert werden - was is also das Problem? 😕
      Denn ich dachte, dass main.cpp sich lediglich die Deklarationen aus der Klasse holt (wo eben keine boost Funktionen drin sind) und anschließend beim Linken die Referenzen aufgelöst werden. Da aber zuvor foo.cpp erfolgreich kompiliert wurde, sind die Referenzen doch vorhanden.

    Viele Grüße,
    Klaus.



  • Klaus82 schrieb:

    1. foo.cpp wird kompiliert. Dabei existiert noch kein FOO_H_ , d.h. zum Einen wird dieses Symbol (diese Variable?) angelegt und anschließend alles includiert.

    Richtig. (Bis auf die Wortwahl: Es ist weder ein Symbol noch eine Variable, sondern ein Präprozessorsymbol)

    1. main.cpp wird kompiliert. Es fügt foo.h und check, ob FOO_H_ bereits existiert - jap, tut es.

    Falsch. Neue Übersetzungseinheit (neue .cpp-Datei), also sind auch alle Präprozessorsymbole weg.



  • Klaus82 schrieb:

    Ich dachte das mit den include guards funktioniert so:

    1. foo.cpp wird kompiliert. Dabei existiert noch kein FOO_H_ , d.h. zum Einen wird dieses Symbol (diese Variable?) angelegt und anschließend alles includiert.
    2. main.cpp wird kompiliert. Es fügt foo.h und check, ob FOO_H_ bereits existiert - jap, tut es.

    Nein, tut es nicht.

    Schau dir nochmal an, wie der Präprozessor funktioniert. Du kannst beim gcc auch mit gcc -E den Code nach dem Präprozessor ausgeben lassen, das ist vielleicht mal ganz interessant.



  • SG1 schrieb:

    1. main.cpp wird kompiliert. Es fügt foo.h und check, ob FOO_H_ bereits existiert - jap, tut es.

    Falsch. Neue Übersetzungseinheit (neue .cpp-Datei), also sind auch alle Präprozessorsymbole weg.

    Hä? 😕

    Ich dachte diese include guards sollen helfen, falls eine Datei in verschiedene Dateien öfter eingebunden wird. Falls diese Präprozessorsymbole aber bei jeder dieser verschiedenen Dateien wieder verworfen werden, wie kann die include guard dann helfen?

    Ich dachte das sei genau dafür gedacht, dass ich nicht noch einmal alles neu einbauen musse, wenn es bereits (wie z.B. im Falle von foo.h ) geschehen ist. Aber das ist gerade nicht der Fall? 😕 ?

    Gruß,
    Klaus.



  • Include Guards sollen verhindern, dass ein Header innerhalb einer Übersetzungseinheit mehrfach eingebunden wird (z.B. indirekt über andere Header).



  • Include Guards herlfen nur dagegen:

    #include "foo"
    #include "foo"
    

    Der Include Guard fängt das zweite Include ab und verhindert damit Compilerfehler.
    In der echten Welt ist es natürlich eher so dass du a und b inkludierst die zufälligerweise beide c inkludieren. Ohne Include Guard hättest du 2x c eingebunden.



  • Bashar schrieb:

    Schau dir nochmal an, wie der Präprozessor funktioniert. Du kannst beim gcc auch mit gcc -E den Code nach dem Präprozessor ausgeben lassen, das ist vielleicht mal ganz interessant.

    Boa, was ist das denn? Ein simples hello world Programm liefert bei der -E Option eine Ausgabe von ~17.000 Zeilen. 😮
    Ich sehe schon, ich wieder viel zu lernen habe ... 🤡

    Aber was ist jetzt der richtige Ansatzpunkt, um weiter zu machen?

    Gruß,
    Klaus.



  • Klaus82 schrieb:

    Aber was ist jetzt der richtige Ansatzpunkt, um weiter zu machen?

    Du meinst abgesehen davon, endlich mal zu verstehen, was der Präprozessor macht? In main.cpp das includieren, was du dort brauchst.



  • Klaus82 schrieb:

    Aber was ist jetzt der richtige Ansatzpunkt, um weiter zu machen?

    Wenn boost nur in foo.cpp verwendet wird, gehört die Includeanweisung auch dahin und nicht in den Header.

    Übersetzt du jede Datei einzeln per Compileraufruf? Includepfade werden normalerweise im Makefile oder dem "Projekt" der IDE global gesetzt => das Problem existiert nicht mehr.



  • manni66 schrieb:

    Übersetzt du jede Datei einzeln per Compileraufruf?

    Ich dachte das ist der Vorteil bzw. Gedanke von Objektorientiert programmieren?

    Ich bastle eine Klasse und teile die Deklaration und Implementierung auf header und cpp Datei auf. Dann kompiliere ich die cpp Datei.

    Ich muss meinem Kollegen also lediglich sagen, wie er die src file zu kompilieren hat, z.B. boost Verzeichnis includieren und wie die Memberfunctions aufgerufen werden.

    Wenn mein Kollege aber jetzt in jeder Datei, die meine Klasse verwendet, wiederholt z.B. boost includieren muss, dann wird er sich zu recht aufregen.

    Oder ist das kein Inhalt von OOP, sondern Präprozessor bzw. Compiler?

    Gruß,
    Klaus.



  • Klaus82 schrieb:

    manni66 schrieb:

    Übersetzt du jede Datei einzeln per Compileraufruf?

    Ich dachte das ist der Vorteil bzw. Gedanke von Objektorientiert programmieren?

    Nein



  • Okay.

    Dann stelle ich die zu durchsuchenden Pfade einfach global ein und die Sache hat sich erledigt.

    Viele Grüße,
    -- Klaus.


Log in to reply