Anfängerfrage: Header > Preproceser > Quelldatei: Funktionsweise & Unnötiger Code?



  • Das hast du leider zum Großteil richtig erfasst. #include ist tatsächlich simple Textersetzung. Theoretisch muss das bei Standardheadern wie <iostream> nicht so sein, ist es aber in der Praxis.



  • Deine Überlegung ist richtig. Das ganze Verfahren ist sehr ineffizient. Das Problem wird mit den in C++ 20 eingeführten Modules hoffentlich gelöst.

    Die meisten Compiler bieten precompiled header an, die den Arbeitsaufwand etwas reduzieren.



  • Zusatzfrage:
    Interpretiere ich die Aussage von @DirkB dahingehend richtig, daß im ausführbaren Programm eine "C++ Runtime Library" enthalten ist, die jedoch nur einmal vorhanden ist, und deren Funktionen bei Bedarf ausgeführt werden.
    ... oder werden deren Funktionen im Laufe des Compelierungsvorgang an den entsprechenden Stellen in den "Quellcode" eingefügt.
    ... oder ?

    Da nun für mich feststeht, daß während dem präprozes "unnötiger" Code eingefügt wird, stellt sich nun natürlich auch die Frage ob und wann dieser später auch wieder entfernt wird.
    Gibt es Möglichkeiten Code dahingehend zu optimieren das unnötiger "Code" im ausführbaren Programm weitgehend vermieden wird, oder um ihn irgend wann vor dem Linken irgendwie wieder zu entfernen.
    Sprich, ist das ganze nur eine Zeitfrage während dem Compelieren oder hat es auch Auswirkungen auf das ausführbare Programm?



  • @axam sagte in Anfängerfrage: Header > Preproceser > Quelldatei: Funktionsweise & Unnötiger Code?:

    daß im ausführbaren Programm eine "C++ Runtime Library" enthalten ist, die jedoch nur einmal vorhanden ist, und deren Funktionen bei Bedarf ausgeführt werden.

    Die Runtimelibrary kann statisch oder dynamisch gelinkt werden.

    Statisch ist sie dann in der .exe drin, natürlich nur einmal.
    Dynamisch als DLL, dann ist sie eine extra Datei, die zur Laufzeit geladen wird.

    ... oder werden deren Funktionen im Laufe des Compelierungsvorgang an den entsprechenden Stellen in den "Quellcode" eingefügt.

    Ja, bei Inline-Funktionen

    Da nun für mich feststeht, daß während dem präprozes "unnötiger" Code eingefügt wird,

    Das siehst du falsch.
    Du solltest da zwischen Code (der irgendwann Speicher belegt) und Informationen (für den Compiler) unterscheiden.



  • @DirkB
    Vielen Dank für deine Antwort.
    Bei deiner letzte Antwort möchte ich jedoch nochmal nachhacken, den sie trifft genau den Kern.
    Mir ist durchaus bewußt, daß es einen Unterschied gibt zwischen Quellcode, Compilercode und ausführbarem Programm.
    @DirkB sagte in Anfängerfrage: Header > Preproceser > Quelldatei: Funktionsweise & Unnötiger Code?:

    @axam sagte in Anfängerfrage: Header > Preproceser > Quelldatei: Funktionsweise & Unnötiger Code?:

    Da nun für mich feststeht, daß während dem präprozes "unnötiger" Code eingefügt wird,

    Das siehst du falsch.
    Du solltest da zwischen Code (der irgendwann Speicher belegt) und Informationen (für den Compiler) unterscheiden.

    Und genau diesen Unterschied versuche ich gerade herauszufinden.

    Wie ich herausgefunden habe (und meine Befürchtung wurde dann hier im Forum bestätigt) fügt der Präprozesor "unnötigen" Code in meinen QuellCode ein.

    Wenn dieser "unnötige" Code dann vom Compiler in Maschinensprache übersetzt wird und vom Linker dann in das ausführbare Programm übernommen wird, würde ich gerne irgend wie das ausführbare Programm "bereinigen" - zwar ungeachtet der Sinnhaftigkeit des Ganzen, jedoch am Besten ohne einen eigenen "Compiler" schreiben zu müssen.

    Wenn andererseits der Präprozeser, zwar "unnötig" Code eingefügt, dafür aber dann der Compiler oder der Linker alles ignoriert was unnötig ist, dann wäre das ganze, vor allem jetzt wo ich weiß, daß auch die eigentlichen Funktionen "seperat" (also nur einmal) eingefügt werden, nur ein sekundäres Problem, das ich, solange sich die Compeilerzeit noch in Grenzen hält, vorerst vernachlässigen kann.





  • In den Headerdateien stehen nur Deklarationen (z.B. Makros, Templates, Klassen- und Funktionsdeklarationen, ...), welche nur Informationen für den Compiler (bzw. Präprozessor) sind, um Namen ("Identifiers") (und dahinterstehende Typen) zu erkennen.
    Nur wenn im Source-Code selbst eine dieser Namen benutzt wird, dann wird auch effektiv Code dafür erzeugt.

    Solange du also nur z.B. std::cout und std::endl aus <iostream> benutzt, wird auch nur dafür (bei statischer Einbindung der C++ Runtime Library) Code in die ausführbare Datei übernommen.
    Und bei Inline-Funktionen wird dann auch für jeden Aufruf Code erzeugt.

    Nur bei nicht-inline Funktionen oder dynamischer Einbindung von Library Funktionen wird nur ein Verweis auf das Objekt (Variable oder Funktion) in der erzeugten "object"-Datei (".obj") hinterlegt, so daß der Linker dann diese Abhängigkeiten auflösen kann (anhand der ".lib"-Dateien der Libraries).
    Und erst beim Ausführen des Programms werden dann die zugehörigen DLLs (in denen der Code für die externen Funktionen enthalten ist) vom Betriebssystem gesucht und geladen (und intern dann die passenden Funktionszeiger [per "Relokationseintrag"] dafür gesetzt), s.a. Portable Executable (PE) sowie der verlinkte Artikel Common Object File Format (wenn du verstanden hast, wie EXE- und DLL-Dateien etc. aufgebaut sind, dann kriegst du ein besseres Verständnis dafür, was der Compiler und Linker intern genau machen).



  • @axam sagte in Anfängerfrage: Header > Preproceser > Quelldatei: Funktionsweise & Unnötiger Code?:

    Wie ich herausgefunden habe (und meine Befürchtung wurde dann hier im Forum bestätigt) fügt der Präprozesor "unnötigen" Code in meinen QuellCode ein.

    Ich versuche dich gerade von dieser Angst abzubringen.

    Wenn dieser "unnötige" Code dann vom Compiler in Maschinensprache übersetzt wird

    Solcher Code steht nicht in Headerdateien - also Etwas, das in Maschinensprache übersetzt wird.

    PS: der Compiler hat mehr Verwaltungsaufwand, da er Informationen erhält die er später nicht braucht. Das macht die .exe aber nicht größer.



  • Genau, dies würde dann die One Definition Rule (ODR) verletzten und vom Linker angemeckert werden.



  • Dann sage ich jetzt danke an alle. Von meiner Seite her ist meine Frage jetzt soweit beantwortet.

    Und dank an @Th69, dafür, daß du die Funktionsweise etwas ausführlicher aufgeschlüsselt hast, jetzt verstehe ich das Zusammenspiel der einzelnen Komponenten (und was am ende als 0&1 übrigbleibt) schon deutlich besser - und für meine Zwecke erstmal ausreichend genug.