Gegenseitige Includes, zyklische Abhängigkeiten



  • Hallo zusammen,

    Wenn ich probiere folgende Files zu compilieren kommt immer der Fehler
    syntax error before "QATuple" in manager.h.

    Was zum Henker mache ich falsch. Sitze schon mehrere Stunden an dem Problem
    und komme nich weiter.

    Benutze MinGw mit Eclipse, hab es aber auch in Visual Studio versucht mit gleichem Resultat.

    Eine Sache konnte ich rausfinden, wenn ich die Source Datei uestion.c aus
    dem Projekt rausschmeiße und nicht mitcompiliere kommt kein Fehler.

    ich habe folgende Source und Header Files

    manager.h

    #ifndef MANAGER_H_
    #define MANAGER_H_
    #include "uestion.h"
    
    int getNewQATupel(int p1, QATuple *qa);
    
    #endif
    

    manager.c

    #include "manager.h"
    #define MAX 25
    
    int getNewQATupel(int p1, QATuple *outAnswer){
    	return 0;
    }
    

    uestion.h

    #ifndef UESTION_H_
    #define UESTION_H_
    #include "manager.h"
    
    typedef struct questionAnswersTuple{
    	const char* question;
    	const char* answer;
    	const char* wrongAnswers[3];
    }QATuple;
    
    typedef enum success {
    	FAIL, PASS, EXIT
    }SUCCESS;
    
    SUCCESS ask(QATuple* question, int* Punkte, int* fiftyJoker, int* changeJoker);
    
    #endif
    

    uestion.c

    #include "uestion.h"
    
    SUCCESS ask2(QATuple* question, int anzahl, int* punkte, int* fiftyJoker, int* changeJoker);
    
    SUCCESS ask(QATuple* question, int* punkte, int* fiftyJoker, int* changeJoker) {
    	return ask2(question, 4, punkte, fiftyJoker, changeJoker);
    }
    
    SUCCESS ask2(QATuple* question, int anzahl, int* punkte, int* fiftyJoker,
    		int* changeJoker) {
    return FAIL;
    }
    

    Bitte helft mir

    Mfg
    roskas



  • manager.h und uestion.h inkludieren sich gegenseitig. In uestion.c führt das dazu, daß QAtuple unbekannt ist, weil dort zuerst uestion.h inkludiert wird, dort wird zuerst UESTION_H definiert, jetzt wird manager.h inkludiert. Hier wiederum wird wieder uestion.h inkludiert, allerdings ist jetzt wegen der bereits erfolgten Definition von UESTION_H dieser Include wirkungslos und deshalb QATuple in manager.h unbekannt.



  • mal alles in der c-datei auskommentieren und schrittweise hinzufügen, bis fehler identifiziert.



  • Ja es liegt tatsächlich am gegenseitigen includen.

    1. Lösungsmöglichkeit (leicht verändertes Beispiel):
    Dazu muss man in den Headerdateien erst die sachen definieren, die in den anderen Headerdateien benötigt werden und danach erst diese Headerdateien includen.

    manager.h

    #ifndef MANAGER_H_
    #define MANAGER_H_
    
    typedef enum _level {
    	HAUS, AUTO, STUHL
    } Level;
    
    #include "uestion.h"
    
    void machwas(Haus haus);
    #endif
    

    manager.c

    #include "manager.h"
    
    void machwas(Haus haus){}
    

    uestion.h

    #ifndef UESTION_H_
    #define UESTION_H_
    
    typedef struct ha{
    	int nutzer;
    }Haus;
    
    #include "manager.h"
    
    void setLevel(Level l);
    
    void test();
    #endif
    

    uestion.c

    #include "uestion.h"
    
    void test(){}
    void setLevel(Level l){}
    

    2. Lösungsmöglichkeit
    Zitat Prof:
    "In der Regel werden bei solch enger Verzahnung von zwei
    Modulen die grundlegenden Datenstrukturen (hier die Typdefinitionen) in
    eine separate Header-datei ausgelagert, zu der es dann keine .c-Datei gibt.
    "

    Oder hat jemand noch andere Möglichkeiten die funktionieren?

    Mfg
    roskas



  • Wenn ich mir Dein erstes Posting ansehe, glaube ich, daß Du dort in uestion.h die Funktionsdeklaration aus manager.h nicht benötigst.
    Also wirf das Include aus uestion.h hinaus.



  • In der Regel werden bei solch zyklischen Abhängigkeiten Deklarationen verwendet, um dem Compiler mitzuteilen, dass es einen bestimmten Typ gibt, aber nicht, was dieser enthält. Deklarationen (in diesem Zusammenhang auch Vorausdeklarationen genannt) sind überall dort ausreichend, wo der Compiler den Inhalt eines Typs nicht kennen muss.

    Beispiel:

    #ifndef MANAGER_H_
    #define MANAGER_H_
    // hier stehen die Innereien von QATuple drin. Die brauchen wir hier aber noch nicht.
    // #include "uestion.h" 
    
    // getNewQATupel wird ein Zeiger übergeben. Dem Compiler reicht es, zu wissen, dass QATuple ein Typedef einer Struktur ist.
    typedef struct questionAnswersTuple QATuple;
    int getNewQATupel(int p1, QATuple *qa);
    
    #endif
    

    Erst in der Implementierung von getNewQATupel muss die Struktur (vermutlich) bekannt sein. Deshalb musst Du in manager.c sowohl manager.h als auch uestion.h einbinden.

    BTW: Meiner Meinung nach ist das include manager.h in uestion.h völlig unnötig.


Anmelden zum Antworten