HeaderDatei - doppelte Includes ?



  • fkt.h

    #include <stdio.h>
    
    void test (void);
    

    fkt.cpp

    #include "fkt.h"
    
    void test (void)
    {
    printf("test");
    }
    

    main.cpp

    #include <stdio.h>
    #include "fkt.h"
    
    int main (void)
    {
    test();
    printf("test");
    }
    

    Also man sieht hier ein einfaches Bespiel zu einer Headerdatei, die Frage ist kann man umgehen das zweimal <stdio.h> eingebunden wird?

    Gruß



  • Jup, ist schon.
    Stichwort: include guards



  • Ja die sind mir bekannt.

    #pragma once

    o.

    #ifndef TEST_H
    #define TEST_H

    #endif

    Nur würde es trotzdem doppelt <stdio.h> einbinden.



  • Der Compiler braucht in jeder Übersetzungseinheit einmal den Header, wenn Funktionen daraus verwendet werden. Natürlich sollte der Compiler soweit optimiert sein, dass er die Datei nur einmal im Speicher hält.



  • Tron123 schrieb:

    Nur würde es trotzdem doppelt <stdio.h> einbinden.

    Wobei das zweite mal dank include guards nichts tut!
    Manche Compiler sind sogar soweit in der Lage das zu erkennen und die Datei noch nicht einmal zu öffnen.



  • Kommt darauf an wie man es sieht. Im Endeffekt wird die Datei dreimal eingebunden, einmal in der Übersetzungseinheit von fkt.cpp, in der Übersetzungseinheit von main (1. include) und noch einmal in der Übersetzungseinheit von main über fkt.h. Das zweite in main wird von den Include-Guards verhindert, d.h. es bleiben noch zwei, eine pro Übersetzungseinheit.



  • patrick246 schrieb:

    Das zweite in main wird von den Include-Guards verhindert, d.h. es bleiben noch zwei, eine pro Übersetzungseinheit.

    Und das kann und soll man auch nicht verhindern, da jede Übersetzungseinheit die Deklaration aus cstdio braucht, da sie sonst nicht kompilieren würde.



  • Nathan schrieb:

    Manche Compiler sind sogar soweit in der Lage das zu erkennen und die Datei noch nicht einmal zu öffnen.

    Jo, wobei der Effekt von diesem Trick eher vor 20 Jahren wichtig war, bei Speichermangel in Win95 auf Drehplatten. MS hatte dazu #pragma once erfunden, gcc erkannte die normalen include-guards.

    Jetzt können alle #pragma once, aber keiner braucht's. 😃
    http://en.wikipedia.org/wiki/Pragma_once#Portability

    # time ( find / -iname '*.h' | wc -l )
    258190
    real	0m3.396s
    user	0m1.745s
    sys	0m1.621s
    
    # time ( find / -iname '*.h' -print0 | xargs -0 head -n2 > t )
    real	0m5.314s
    user	0m2.898s
    sys	0m3.271s
    

    Aha, Datei-Öffnen und die ersten beiden Zeilen lesen packt er so um die 100000 pro Sekunde.

    edit: Ups, das war gemessen unter voller Prozessorauslastung von anderen Prozessen. Im Idle sieht's sp aus:

    # time ( find / -iname '*.h' | wc -l )
    258190
    real	0m3.042s
    user	0m1.616s
    sys	0m1.470s
    
    # time ( find / -iname '*.h' -print0 | xargs -0 head -n2 > t )
    real	0m3.143s
    user	0m2.082s
    sys	0m2.142s
    

    also vielleicht eher 1Mio unoptimierte include-guards pro Sekunde.



  • Tron123 schrieb:

    fkt.h

    #include <stdio.h>
    void test (void);
    

    Also man sieht hier ein einfaches Bespiel zu einer Headerdatei, die Frage ist kann man umgehen das zweimal <stdio.h> eingebunden wird?

    wozu mußt Du überhaupt in fkt.h <stdio.h> inkludieren ? Wenn die Implementation einer Funktion in fkt.cpp diese include braucht, reicht es doch, #include <stdio.h> in die .cpp-Datei zu schreiben. Und zweitens, ich inkludiere immer nur dann, wenn es wirklich gebraucht wird, d.h. nur dann, wenn es ohne das include nicht zu linken ist. Damit fiele #include<stdio.h> in main.cpp weg und das Problem stellt sich *hier* nicht. In anderen Situationen könnte es aufw{e|ä}ndig sein, mehrfache includes zu umgehen, dann lösen include guards in jeder .h Datei das Problem einfach und wirkungsvoll.



  • großbuchstaben schrieb:

    Und zweitens, ich inkludiere immer nur dann, wenn es wirklich gebraucht wird, d.h. nur dann, wenn es ohne das include nicht zu linken ist. Damit fiele #include<stdio.h> in main.cpp weg und das Problem stellt sich *hier* nicht.

    Die main verwendet unmittelbar printf() und deshalb soll sie die <stdio.h> inkludieren. Sonst machste ja die Dateien nicht mehr davon abhängin, was sie tun, sondern davon was andere Datein tun, das wird möglicherweise so ein schlimmer HeckMeck, daß man die Lust verliert und anfängt, großzügig zu inkludieren. Die "fkt.h" sollte die <stdio.h> hingegen nicht inkludieren, aber dafür sollte die "fkt.cpp" es wieder machen, denn sie verwendet auch printf().

    Und es reicht, auf den Compiler zu achten, was man mindestens inkludieren muss: Haste den erstmal überzeugt, ist im Allgemeinen auch der Linker mit dem Inkludieren zufrieden.



  • volkard schrieb:

    Sonst machste ja die Dateien nicht mehr davon abhängin, was sie tun, sondern davon was andere Datein tun, das wird möglicherweise so ein schlimmer HeckMeck, daß man die Lust verliert und anfängt, großzügig zu inkludieren.

    das hängt von der Konsequenz ab, würde ich sagen. Benötigt eine Datei A.h nach Bearbeitung mehr #includes als voher, sagt mir der Compiler das schon. Dann prüfe ich, ob diejenigen DAteien, die A.h inkludieren, nun überflüssige #includes besitzen und passe sie ggf an.

    Ab einem bestimmten Reifungsgrad ändert sich der #include-Graph meinen Erfahrungen nach sowieso seltener oder nur noch bei Refactorings und größeren Erweiterungen.


Log in to reply