Anzeige:
Ergebnis 1 bis 9 von 9

Thema: [C] Was muss genau in einen Header?

  1. #1
    Registrierter Benutzer Avatar von roadracer
    Registriert seit
    16.02.2010
    Ort
    Wolfenbüttel
    Beiträge
    48

    [C] Was muss genau in einen Header?

    Hallo,
    bitte entschuldigt, wenn man bei Google schnell eine Lösung findet, aber ich weiß einfach nicht wirklich wo nach ich suchen soll.
    Es kommt jetzt nicht die 0815-Frage, "wie erstelle ich meine eigenen Header", sondern viel speziellere Sachen, die man aus den 0815-Beispielen, die Google anbietet nicht erkennen kann.
    Also,

    1. Gibt es einen Unterschied zwischen Header für Objektdateien und Header für Bibliotheken? Wegen Linken, etc. (Siehe Frage 2)
    2. Kommen in den Header auch die Präpozessor-Derektieven, wie z.B. #define und #include, der Quelldateien? Denn Objektdateien werden erst später gelinkt, und damit ja auch die Header/Bibliotheken.
    3. Kommen struct und union Definitionen (oder heißt es doch Deklarationen?) auch in den Header?

    VG roadracer
    OpenSUSE 12.1 x86 KDE 4.7

    Alle Rechtschreibfehler unterliegen der GFDL und dürfen so oder in veränderter Form genutzt und weiter gegeben werden.

  2. #2
    Registrierter Benutzer Avatar von sommerfee
    Registriert seit
    02.07.2006
    Beiträge
    1.603
    Was genau meinst du mit "Header"? Die .h-Datei?

    Zitat Zitat von roadracer Beitrag anzeigen
    [*]Gibt es einen Unterschied zwischen Header für Objektdateien und Header für Bibliotheken?
    Nein, ob eine Funktion in einer anderen C-Datei, in einer Objektdatei oder in einer Bibliothek steckt, ist für die H-Datei (fast) irrelevant. Fast deswegen, weil z.B. der MS-Compiler Preprozessor-Direktiven kennt, die dafür sorgen, daß bestimmte Bibliotheksdateien automatisch hinzugelinkt werden, dies also nicht in den Linker-Optionen angegeben werden muß.

    Kommen in den Header auch die Präpozessor-Derektieven, wie z.B. #define und #include, der Quelldateien?
    Das kommt darauf an. Alles (Makros, Definitionen, Prototypen etc.), was der Anwender der dazugehörigen Funktionen braucht, um diese Funktionen verwenden zu können, ist in der Regel im dazugehörigen Header, wie z.B. stdio.h für die Definition von FILE und den Prototypen von fopen() etc. (Ansonsten könnte der Anwender, der keinen Zugriff auf den Quelltext der Funktionen hat, die Funktionen gar nicht verwenden.)

    Alles, was der Quelltext der Funktionen braucht, aber den Anwender der Funktionen nichts angeht (interne Definitionen etc.), kommt entweder an den Anfang der C-Datei selber, oder aber in eine H-Datei, die der Anwender nicht so einfach einbinden kann/soll.

    Kommen struct und union Definitionen (oder heißt es doch Deklarationen?) auch in den Header?
    Siehe oben.

    Liebe Grüße,
    Axel

  3. #3
    Registrierter Benutzer Avatar von roadracer
    Registriert seit
    16.02.2010
    Ort
    Wolfenbüttel
    Beiträge
    48
    Danke schon mal, aber die Geschichte mit den #include-Derektieven ist mir noch etwas zu schwammig. Muss ich die nun auch in den Header eintragen? Eigentlich nicht, oder? Denn es geht den Anwender ja nix an.

    Was genau meinst du mit "Header"? Die .h-Datei?
    dito
    OpenSUSE 12.1 x86 KDE 4.7

    Alle Rechtschreibfehler unterliegen der GFDL und dürfen so oder in veränderter Form genutzt und weiter gegeben werden.

  4. #4
    Registrierter Benutzer Avatar von sommerfee
    Registriert seit
    02.07.2006
    Beiträge
    1.603
    Wenn du mit "Header" keine "Header-Dateien" meinst, ist die Antwort einfach: In C gibt es keinen Header.

    Code:
    int quad( int x )
    {
      return x * x;
    }
    int a;
    #include <stdio.h>
    int main( void )
    {
    #define X 4
      printf( "%d^2 = %d\n", X, a = quad( X ) );
      return a;
    }
    Wo ist da jetzt der Header?

    Ein #include macht intern nichts weiter, als vor dem Übersetzen des Quelltextes den Inhalt der angegebenen Datei an der Stelle einzufügen, wo das #include steht. Da kann an C-Code drinstehen was will.

    Üblicherweise schreibt man die #includes an den Anfang des Quelltextes, aber das ist keine Regel und schon gar keine Notwendigkeit, lediglich eine Konvention, mehr nicht.
    Geändert von sommerfee (19-08-2010 um 07:08 Uhr)

  5. #5
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von roadracer Beitrag anzeigen
    Gibt es einen Unterschied zwischen Header für Objektdateien und Header für Bibliotheken? Wegen Linken, etc. (Siehe Frage 2)
    Wie sommerfee schon geschrieben hat, gibt es im ersten Moment keinen Unterschied. Allerdings ist die Sache mit den Symbol Direktiven nicht nur auf den Microsoft Compiler beschränkt, auch wenn man es dort am leichtesten als Problem bekommt.

    Generell kennen die meisten Compiler heutzutage sogenannten Symbolsichtbarkeit, d.h. Symbole wie Funktionsnamen können vom Compiler so in der Bibliothek abgelegt werden, dass sie "unsichtbar" werden.
    In diesem Fall sind sie zwar für anderen Code aus der Bibliothek selbst vorhanden, aber nicht für Programmcode der die Bibliothek benutzt.

    Oft kommt man erstmal ohne aus, z.B. weil man nur statische Bibliotheken erzeugt, oder die entsprechende Compileroption aus ist.
    Wenn man mal so ein Macro hat, ist es aber auch nicht sehr viel Aufwand, es entsprechend anzubringen.

    Kommen in den Header auch die Präpozessor-Derektieven, wie z.B. #define und #include, der Quelldateien? Denn Objektdateien werden erst später gelinkt, und damit ja auch die Header/Bibliotheken.
    Ich bin mir da nicht ganz sicher wie Sommerfee das gemeint hat, aber es gibt da unterschiedliche Strategien.

    Es kann Sinn machen, alle Sachen einer Bibliothek in einem Header zu haben (bzw. einen Header, der alle anderen inkludiert).
    Das ist sehr bequem, setzt aber praktisch eine Buildchain mit Unterstützung für Precompiled Headers vorraus (weil sonst für jede Quelldatei das ganze Ding durch gearbeitet werden müsste).

    Eine andere Strategie ist, nur die Sachen zu inkludieren, die absolut notwendig für den Compiler sind, nicht unbedingt für die Benutzung.

    Beispiel:
    nehmen wir an man hat eine Structure
    Code:
    struct Foo {
      int bar;
    };
    und in einem anderen Header eine Funktion, die diese Structure benutzt
    Code:
    int foo_bar( Foo *foo );
    Der Compiler muss nun dafür nur über Foo Bescheid wissen, er braucht zu diesem Zeitpunkt noch kein Details, weil hier aussreicht, dass er weiß es ist ein Pointer.

    D.h. es ist nicht falsch den Header für Foo zu inkludieren, man kann es aber auch mit einer sogenannten Forwarddeclaration machen

    Code:
    struct Foo;
    
    int foo_bar( Foo *foo );
    Um foo_bar() zu benutzen, muss man dann beide Header inkludieren.

    Das ist weniger bequem, kann aber dann helfen, wenn viele solcher Abhängigkeiten in einem Header benötigt würden und man aber nicht alle Funktionen aufrufen möchte. D.h. man kann dann selektiv die Abhänigigkeiten dort inkludieren, wo man sie auch wirklicht braucht.

    Kommen struct und union Definitionen (oder heißt es doch Deklarationen?) auch in den Header?
    Generell ja, es sei denn, es sind "private" Datenstrukturen.
    Das wird besonders bei Bibliotheken gern gemacht, um Implementationsdetails aus der API raus zuhalten und später die Möglichkeit zu haben diese zu ändern ohne dass davon abhängige Software neu gebaut oder sogar verändert werden muss.

    Beispiel:
    nehmen wir an deine Bibliothek hat Operationen auf Rechtecken. Mit einer öffentlichen Struct sieht das vielleicht so aus

    Code:
    struct Rect {
      int x;
      int y;
      int width;
      int height;
    };
    
    int area_size( Rect* rect );
    Jemand kann also eine Instanz von Rect z.B. so befüllen
    Code:
    rect->x = 5;
    rect->y = 10;
    Zu einem späteren Zeitpunkt würdest du gerne Rect so ändern, dass es in Paar von gegenüberliegenden Eckpunkten ist.

    Code:
    struct Rect {
      int x1;
      int y1;
      int x2;
      int y2;
    };
    Das sind zwar wieder vier int, aber die Namen und die Bedeutung haben sich geändert.

    Bei einer privaten oder "opaque" (also nicht durchsichtig) Structure sieht das in etwa so aus
    Code:
    struct Rect;
    
    Rect *create_empty_rect();
    void rect_set_x( iRect *rect, int x );
    void rect_set_width( Rect *rect, int w );
    Im Falle der ersten Variante sehen die Implementierung der beiden Funktionen so aus
    Code:
    void rect_set_x( Rect *rect, int x )
    {
      rect->x = x;
    }
    
    void rect_set_width( Rect *rect, int w )
    {
      rect->width = w;
    }
    Im Falle der zweiten Variante z.B. so:
    Code:
    void rect_set_x( Rect *rect, int x )
    {
      rect->x1 = x;
    }
    
    void rect_set_width( Rect *rect, int w )
    {
      rect->x2 = rect->x1 + w;
    }
    Es macht die Benutzung komplizierter, aber behält mehr Spielraum für die Implementierung.
    Bei einfachen Strukturen wird man das meistens eher nicht machen, aber wenn man sich Sachen erweiterbar halten will, kann das manchmal die einzige Lösung sein.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  6. #6
    Registrierter Benutzer Avatar von roadracer
    Registriert seit
    16.02.2010
    Ort
    Wolfenbüttel
    Beiträge
    48
    Danke noch mal für die Antworten!

    Wenn du mit "Header" keine "Header-Dateien" meinst, ist die Antwort einfach: In C gibt es keinen Header.
    Doch, genau die meine ich.

    100% klar ist mir die Geschichte mit dem #include in Headern aber immer noch nicht.
    Ein Beispiel:
    Ich haben zwei Quelldateien main.c und funktion.c, sowie den Header funktion.h, wobei ich aus main.c und funktion.c erst Objektdateien machen möchte, die ich dann Linke.

    main.c
    Code:
    #include <stdio.h>
    #include "funktion.h"
    
    int main () {
    int einezahl = 1618
    funktion_eins (einezahl);
    return 0;
    }
    funktion.c
    Code:
    #include <stdio.h>
    
    void funktion_eins (int irgendeinezahl) {
    printf ("%i\n", irgendeinezahl);
    }
    funktion.h
    Code:
    #ifndef FUNKTION_H
    #define FUNKTION_H
    
    void funktion_eins (int irgendeinezahl);
    
    #endif
    Meine Frage ist jetzt, muss in funktion.h auch ein #include <stdio.h>? Denn wenn ich jetzt nur assembliere, wird ja die stdio-Bibliothek (-Dings?) nicht gelinkt. Wenn ich dann aber main.o und funktion.o linke, müsste der Compiler nichts mehr von der noch benötigten stdio-Bibliothek (-Dings?)
    wissen.
    Oder doch? Wird sie schon in die Objektdatei mit gelinkt? Und würde sie dann nicht doppelt in das ausführbare Kompilat einfließen und es nur unnötig groß machen?

    Wie man sieht birgt diese Geschichte bei mir noch einige Fragen.

    VG roadracer
    OpenSUSE 12.1 x86 KDE 4.7

    Alle Rechtschreibfehler unterliegen der GFDL und dürfen so oder in veränderter Form genutzt und weiter gegeben werden.

  7. #7
    Registrierter Benutzer Avatar von sommerfee
    Registriert seit
    02.07.2006
    Beiträge
    1.603
    Zitat Zitat von roadracer Beitrag anzeigen
    Meine Frage ist jetzt, muss in funktion.h auch ein #include <stdio.h>?
    Nur dann, wenn in funktion.h Dinge verwendet werden, die in stdio.h definiert sind, also wenn z.B. in funktion.h ein Prototyp "int irgend_eine_funktion( FILE *fp );" stehen würde. Ohne das #include <stdio.h> würde es dann eine Fehlermeldung geben, wenn man in einem Quelltext #include "funktion.h" ohne vorheriges #include <stdio.h> stehen hätte. In deinem Falle also nicht.

    Übrigens würde ich auch in funktion.c ein #include <funktion.h> schreiben, auch wenn es nicht zwingend notwendig ist. Warum? Weil dann der Compiler die Gelegenheit hat, eine Fehlermeldung auszuwerfen, wenn die in funktion.h und funktion.c definierten Funktionen nicht in Rückgabewert und/oder ihren Parametern übereinstimmen.

    Wenn ich dann aber main.o und funktion.o linke, müsste der Compiler nichts mehr von der noch benötigten stdio-Bibliothek (-Dings?) wissen.
    Wenn man Dinge außerhalb der Standardbibliotheken dazulinken möchte, muß man dies dem Linker sagen. Die stdio-Bibliothek gehört aber zu den Standardbibliotheken, deswegen funktioniert das.

    Wird sie schon in die Objektdatei mit gelinkt?
    Nein.

    Liebe Grüße,
    Axel

  8. #8
    Registrierter Benutzer Avatar von undefined
    Registriert seit
    01.03.2004
    Beiträge
    1.255
    Meine Ergänzung zu den bisherigen Erklärungen und seiner Frage zu Headern in C

    @roadracer
    Weil du anscheinend noch nicht die Arbeitsweise eines Compilers kennst

    Man verwendet in C Hauptsächlich aus dem Grunde Header Dateien um dem Compiler mit zu teilen was sich in dem Quelltext Dokument an Objekten/Funktionen befindet. (An die Anderen - ja ich weis es gibt noch die Traditionelle Variante der Vorankündigung)

    Ein Compiler arbeitet Zeilenweise von Oben nach unten rechts nach links den Quelltext ab.

    Fallstrick - Nehmen wir mal an du hat drei Funktionen im Quellcode.
    Code:
    void funktion_a()
    {
      /* aufruf an „funktion_b“ bringt einen Fehler weil der Compiler noch nicht weiss das
         diese Methode exitiert */
      funktion_b();
    }
    
    void funktion_b()
    {}
    
    int main(void)
    {
      /* aufruf an „funktion_a“ bringt keinen Fehler */
      funktion_a();
    }
    Wenn du jetzt aber eine Header einbindest wird der Compiler diese als Referenz der zu erwartenden Objekte heranziehen.
    PS: Vorraus gesetzt du hast diese dort auch definiert
    Geändert von undefined (19-08-2010 um 18:25 Uhr)
    mfg undefined
    --
    Undefined Behavior (undefiniertes Verhalten) bedeutet meistens etwas ungültiges.
    xhtml Debugger

  9. #9
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von sommerfee Beitrag anzeigen
    Nur dann, wenn in funktion.h Dinge verwendet werden, die in stdio.h definiert sind, also wenn z.B. in funktion.h ein Prototyp "int irgend_eine_funktion( FILE *fp );" stehen würde. Ohne das #include <stdio.h> würde es dann eine Fehlermeldung geben, wenn man in einem Quelltext #include "funktion.h" ohne vorheriges #include <stdio.h> stehen hätte.
    In diesem Fall kann man auch eine Forward Delcaration machen, weil FILE als Pointer benutzt wird.
    Das include <stdio.h> braucht man in den .c Dateien, wi man irgend_eine_funktion() aufruft.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •