C2027 in Struct



  • Hallo.

    Ich nutze structs mit Funktionen. Dabei bekomme ich einen
    Compilerfehler C2027.

    Folgendes Codebeispiel:

    #include <stdio.h>;
    
    typedef struct Type1 {
    	struct Type2* T2;
    
    	Type1(){}
    
    	void DoSomething1() {
    		printf("Type1!\n");
    	}
    
    	void DoSomethingElse1() {
    		T2->DoSomething2(); /*ERROR: C2027*/
    	}
    }Type1;
    
    typedef struct Type2 {
    	struct Type1* T1;
    
    	Type2(){}
    
    	void DoSomething2() {
    		printf("Type2!\n");
    	}
    
    	void DoSomethingElse2() {
    		T1->DoSomething1();
    	}
    }Type2;
    
    int main() {
    	Type1 T1;
    	Type2 T2;
    
    	T1.T2 = &T2;
    	T2.T1 = &T1;
    }
    

    Kann ich das irgendwie umgehen? Ich dachte, der Zeigerzugriff ist auch
    bei nicht vollständig definierten Typen erlaubt.



  • CJens schrieb:

    Kann ich das irgendwie umgehen?

    Ja, du kannst das Problem umgehen, indem du mit Vorwärtsdeklarationen arbeitest und den Code sauber in Header- und Sourcedateien aufteilst.

    // edit

    Für alle die die Fehlercodes vom MS Compiler nicht auswendig können:
    C2027 bedeutet "use of undefined type 'type'", siehe https://msdn.microsoft.com/en-us/library/6c2dk0ah.aspx

    // edit2

    Die Verwendung von typedef struct bei der Deklaration und struct X bei der Verwendung sind überflüssig in C++ und rühren von C her.



  • Vorwärtsdeklaration hat hier nicht funktioniert:

    #include <stdio.h>;
    
    typedef struct Type1;
    typedef struct Type2;
    
    typedef struct Type1 {
    	struct Type2* T2 = NULL;
    
    	Type1() { T2 = NULL; }
    
    	void DoSomething1() {
    		printf("Type1!\n");
    	}
    
    	void DoSomethingElse1() {
    		T2->DoSomething2(); /*ERROR: C2027*/
    	}
    }Type1;
    
    typedef struct Type2 {
    	struct Type1* T1 = NULL;
    
    	Type2() { T1 = NULL; }
    
    	void DoSomething2() {
    		printf("Type2!\n");
    	}
    
    	void DoSomethingElse2() {
    		T1->DoSomething1();
    	}
    }Type2;
    
    int main() {
    	Type1 T1;
    	Type2 T2;
    
    	T1.T2 = &T2;
    	T2.T1 = &T1;
    }
    

    Der Fehler besteht weiterhin.

    Das hier ist natürlich nur ein einfaches Beispiel um den Fehler zu reproduzieren. In meinem tatsächlichen Projekt hat jede Struktur eine eigene Header, die in der Source-Datei eingebunden wird.

    Ja, das war tatsächlich ein Projekt, welches ich ursprünglich in C geschrieben hatte und jetzt portiere - da hab ich mir das typedef angewöhnt.



  • Was auch zu erwähnen ist, ich aber dachte, dass sei klar:
    T2 und T1 müssen natürlich auf ein Objekt zeigen, bevor DoSomething...() aufgerufen wird. Aber das ergibt nur Probleme zur Laufzeit, nicht zur Compiletime.



  • Das ist klar.

    Wie gesagt, ist nur ein einfaches Beispiel. Es handelt sich ja um einen Compilerfehler. Es ist dem Beispiel ja nicht dienlich, wenn ich es aufblase und vorher noch eine Abfrage einbaue, welche prüft ob T1 bzw. T2 == NULL sind.



  • Vielleicht hast du in den entsprechenden Sourcedateien vergessen die entsprechende Headerdatei zu inkludieren?



  • In meinem einfachen Beispiel gibt es keine Header Dateien.

    Bei Header-Include kopiert er doch nur den Text rein.

    Ich möchte dieses einfache Beispiel zum Laufen bringen. Dann kann ich es auf mein Programm übertragen.



  • Hier ein kleines Beispiel:

    main.cpp

    #include "X.hpp"
    #include "Y.hpp"
    
    int main()
    {
        X x;
        Y y;
    
        x.y = &y;
        y.x = &x;
    
        x.say_hello_to_y();
        y.say_hello_to_x();
    }
    

    X.hpp

    #ifndef HEADER_X_HPP
    #define HEADER_X_HPP
    
    struct Y;
    
    struct X
    {
        Y* y = nullptr;
        void say_hello_to_y();
        void hello_from_y();
    };
    
    #endif
    

    X.cpp

    #include "X.hpp"
    #include "Y.hpp"
    
    #include <iostream>
    #include <cassert>
    
    void X::say_hello_to_y()
    {
        assert(y != nullptr);
        y->hello_from_x();
    }
    
    void X::hello_from_y()
    {
        std::cout << "Hello from Y\n";
    }
    

    Y.hpp

    #ifndef HEADER_Y_HPP
    #define HEADER_Y_HPP
    
    struct X;
    
    struct Y
    {
        X* x = nullptr;
        void say_hello_to_x();
        void hello_from_x();
    };
    
    #endif
    

    Y.cpp

    #include "Y.hpp"
    #include "X.hpp"
    
    #include <iostream>
    #include <cassert>
    
    void Y::say_hello_to_x()
    {
        assert(x != nullptr);
        x->hello_from_y();
    }
    
    void Y::hello_from_x()
    {
        std::cout << "Hello from X\n";
    }
    


  • CJens schrieb:

    In meinem einfachen Beispiel gibt es keine Header Dateien.

    Bei Header-Include kopiert er doch nur den Text rein.

    Ich möchte dieses einfache Beispiel zum Laufen bringen. Dann kann ich es auf mein Programm übertragen.

    Dann zeig am besten den (Beispiel-) Code, der nicht läuft. Falls das der Code aus deinem ersten Beitrag war, korrigiere ihn bezüglich Vorwärtsdekl. und Unterteilung in Header und Sourcen. Dann zeige ihn wieder mit der kopierten Fehlermeldung.

    // edit

    Falls es sich um den Code aus deinem 2. Beitrag handelt musst du ihn in verschiedene Source-Dateien aufteilen und die entsprechenden struct-Definitionen (die normalerweise inkludiert werden) in diese Source-Dateien hineinschreiben (wenn du keine Header hast/willst).



  • Übertragen auf mein Beispiel:

    StructTest.cpp

    #include <stdio.h>;
    
    #ifndef STRUCT_TYPE_2
    	#include "Type2_Struct.h";
    #endif
    
    #ifndef STRUCT_TYPE_1
    	#include "Type1_Struct.h";
    #endif
    
    int main() {
    	struct Type1 T1;
    	struct Type2 T2;
    
    	T1.T2 = &T2;
    	T2.T1 = &T1;
    }
    

    Type1_Struct.h

    #define STRUCT_TYPE_1
    
    struct Type2;
    
    struct Type1 {
    	struct Type2* T2 = NULL;
    
    	Type1() { T2 = NULL; }
    
    	void DoSomething1() {
    		printf("Type1!\n");
    	}
    
    	void DoSomethingElse1() {
    		T2->DoSomething2();
    	}
    }Type1;
    

    Type2_struct.h

    #define STRUCT_TYPE_2
    
    struct Type1;
    
    struct Type2 {
    	struct Type1* T1 = NULL;
    
    	Type2() { T1 = NULL; }
    
    	void DoSomething2() {
    		printf("Type2!\n");
    	}
    
    	void DoSomethingElse2() {
    		T1->DoSomething1(); /*ERROR: C2027*/
    	}
    }Type2;
    

    Den Compilerfehler bekomme ich aber noch immer.



  • CJens schrieb:

    Vorwärtsdeklaration hat hier nicht funktioniert:
    ...
    Der Fehler besteht weiterhin.

    Vorwärtsdeklaration ist nur der eine Teil. Du kannst T2 erst benutzen, wenn die Deklaration von Type2 bekannt ist, d.h. die Definition von DoSomethingElse1() muss nach der struct Type2 erfolgen.

    #include <iostream>
    
    struct Type2;
    
    struct Type1 {
      Type2* T2 = nullptr;
    
      void DoSomething1() {
        std::cout << "Type1!\n";
      }
    
      void DoSomethingElse1();
    };
    
    struct Type2 {
      Type1* T1 = nullptr;
    
      void DoSomething2() {
        std::cout << "Type2!\n";
      }
    
      void DoSomethingElse2() {
        T1->DoSomething1();
      }
    };
    
    void Type1::DoSomethingElse1() {
      T2->DoSomething2();
    }
    
    int main() {
      Type1 T1;
      Type2 T2;
    
      T1.T2 = &T2;
      T2.T1 = &T1;
    }
    


  • CJens schrieb:

    #ifndef STRUCT_TYPE_2
    	#include "Type2_Struct.h";
    #endif
    
    #ifndef STRUCT_TYPE_1
    	#include "Type1_Struct.h";
    #endif
    

    Includeguards gehören in den Header.



  • Super, danke. 👍 👍 👍

    StructTest.cpp

    #include <stdio.h>;
    
    #ifndef STRUCT_TYPE_2
    	#include "Type2_Struct.h";
    #endif
    
    #ifndef STRUCT_TYPE_1
    	#include "Type1_Struct.h";
    #endif
    
    #ifndef STRUCT_FUNCTIONS
    	#include "Functions.h";
    #endif
    
    int main() {
    	struct Type1 T1;
    	struct Type2 T2;
    
    	T1.T2 = &T2;
    	T2.T1 = &T1;
    }
    

    Type1.h

    #define STRUCT_TYPE_1
    
    struct Type2;
    
    struct Type1 {
    	struct Type2* T2 = NULL;
    
    	Type1() { T2 = NULL; }
    
    	void DoSomething1();
    	void DoSomethingElse1();
    }Type1;
    

    Type2.h

    #define STRUCT_TYPE_2
    
    struct Type1;
    
    struct Type2 {
    	struct Type1* T1 = NULL;
    
    	Type2() { T1 = NULL; }
    
    	void DoSomething2();
    	void DoSomethingElse2();
    }Type2;
    

    Functions.h

    #define STRUCT_FUNCTIONS
    
    void Type1::DoSomethingElse1() { T2->DoSomething2(); }
    void Type1::DoSomething1() { printf("Type1!\n"); }
    
    void Type2::DoSomething2() { printf("Type2!\n"); }
    void Type2::DoSomethingElse2() { T1->DoSomething1(); }
    


  • 🙄



  • CJens schrieb:

    Functions.h

    #define STRUCT_FUNCTIONS
    
    void Type1::DoSomethingElse1() { T2->DoSomething2(); }
    void Type1::DoSomething1() { printf("Type1!\n"); }
    
    void Type2::DoSomething2() { printf("Type2!\n"); }
    void Type2::DoSomethingElse2() { T1->DoSomething1(); }
    

    NEIIIIIIN! cpp!

    INCLUDEGUARDS GEHÖREN IN DEN HEADER! AUCH IN C



  • Ich glaube Cjeans hat überhaupt keine Ahnung vom programmieren .

    Dieses Forum erwartet sehr viel eigenleistung 🕶


Anmelden zum Antworten