partieller Code (include *.c file) schlechter Stil?



  • Guten Morgen,

    eine weitere Frage an Euch;) ich habe einen Pool an verschiede Definition. Nun möchte ich diese Definition in verschiedene Dateien aufteilen zur Übersichtlichkeit bzw. Lesbarkeit.

    Beispiel:

    //pool.h
    typedef struct stDef 
    {
      int someinfo;
    } stDef ;
    
    stDef getDef(const tSIZE id);
    
    //pool.c
    
    #include "foo.c"
    #include "bar.c"
    
    stDef getDef(const tSIZE id)
    {
     static stDef definitions[2]={0};
    definitions [0] = part_Foo();
    definitions [1] = part_Bar();
    
    return stDef [id];
    }
    

    und hier die definitionen:

    //foo.c
    
    static part_Foo()
    {
     stDef def { 42 };
    return def;
    }
    
    //bar.c
    
    static part_Bar()
    {
     stDef def { 123 };
    return def;
    }
    

    aber mir gefällt das nicht so ganz, ist das schlechter still, wie könnte ich das "eleganter" lösen?

    grüße und Danke


  • Mod

    Include von Dateien mit Definitionen drin wird dir normalerweise um die Ohren fliegen, weil du dann mehrfache Definitionen des gleichen Dings bekommst. Ist deshalb bei dir alles static? Weil das den Compiler ruhig gestellt hat?

    Ansonsten musst du zuerst einmal erklären, wieso du das überhaupt gemacht hast. Header sind dir ja offensichtlich bekannt. Wieso benutzt du sie hier nicht?



  • @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    Include von Dateien mit Definitionen drin wird dir normalerweise um die Ohren fliegen, weil du dann mehrfache Definitionen des gleichen Dings bekommst. Ist deshalb bei dir alles static? Weil das den Compiler ruhig gestellt hat?
    Ansonsten musst du zuerst einmal erklären, wieso du das überhaupt gemacht hast. Header sind dir ja offensichtlich bekannt. Wieso benutzt du sie hier nicht?

    ja static erst mal zum "ruhigstellen" der compilers. du meinst ich sollte lieber zu jeder def foo + bar eine header machen.. und dann nur diese includieren.. macht natürlich auch sinn.. 😉 je wo wir drüber reden;)

    dadurch dass nur die die pool.c bar/foo kennt/verwendet .. dachte ich mir ich kann mirfoo.h/bar.h sparen da ich ja direct c includieren kann..

    EDIT: unabhängig davorn, wie könnte ich den so ein pool mit (def) gekappelst sonst designen?


  • Mod

    @SoIntMan sagte in partieller Code (include *.c file) schlechter Stil?:

    ja static erst mal zum "ruhigstellen" der compilers.

    Dass das eine gefährliche Praxis ist, muss ich wohl nicht erklären, oder? Stell dir mal vor, du wärst noch eine Ebene weiter gegangen, hättest pool.c auch ohne Header eingebunden, und daher getDef auch static gemacht. Das wäre ein lustiges Problem.

    du meinst ich sollte lieber zu jeder def foo + bar eine header machen.. und dann nur diese includieren.. macht natürlich auch sinn.. 😉 je wo wir drüber reden;)

    Genau.

    EDIT: unabhängig davorn, wie könnte ich den so ein pool mit (def) gekappelst sonst designen?

    Ist schon okay so, wenn das wirklich zwei Variablen sein sollen, die irgendwie global verfügbar sein sollen. (Warum man gleich mehrere globale Variablen haben sollte, ist natürlich immer zweifelhaft, aber das will ich nicht das Thema machen). Ein allgemeiner Pool sollte natürlich viel weniger statisch sein, aber das ist ja offensichtlich nicht das Ziel, und man muss es ja nicht übertreiben und Dynamik einbauen, die man gar nicht braucht.



  • @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    Ist schon okay so, wenn das wirklich zwei Variablen sein sollen, die irgendwie global verfügbar sein sollen. (Warum man gleich mehrere globale Variablen haben sollte, ist natürlich immer zweifelhaft, aber das will ich nicht das Thema machen). Ein allgemeiner Pool sollte natürlich viel weniger statisch sein, aber das ist ja offensichtlich nicht das Ziel, und man muss es ja nicht übertreiben und Dynamik einbauen, die man gar nicht braucht.

    ja im Endeffekt ,werden die Definitionen später generiert und fixiert, sie fungieren wie templates welche hardcodiert im code hinterlegt sind. konstante Eigenschaften die nie wieder angefasst werden (wie Naturkonstante:) .

    Gibt es einen neues template wird neu versioniert. usw.

    EDIT: deswegen static.. ja ich weiss die const qualifiert fehler noch:)


  • Mod

    @SoIntMan sagte in partieller Code (include *.c file) schlechter Stil?:

    EDIT: deswegen static.. ja ich weiss die const qualifiert fehler noch:)

    Ich würde eher sagen, du hast schon zu viele const in deinem Code.

    So eine Aussage von mir 😲

    Du übergibst sowohl deine Parameter als auch deine Rückgabewerte per Kopien. Wen interessiert, ob du den Parameter dann intern änderst oder nicht? Und Rückgabekopien sind sowieso, ich weiß nicht die C-Terminologie, aber in C++ würde man "R-Value" sagen. Sprich: Du kannst sie sowieso nicht ändern. Du kannst schließlich nicht

    int x(){return 5;}
    
    ...
    
    x() = 6;
    

    machen, egal ob da nun int x() oder const int x() stünde.

    Wenn das natürlich nur vereinfachter Beispielcode ist, und da irgendwelche Pointer eine Rolle spielen, dann ist das const natürlich wichtig. Dann aber um so mehr Vorsicht mit den statics, ob die Objekte, auf die du zeigst, auch wirklich existieren.



  • @SoIntMan

    Mal eine dumme Frage. Was spricht gegen:

    typedef struct stDef 
    {
      int someinfo;
    } stDef ;
    
    
    // Je nach Kontext Foo.h
    static const stDef FooDef = { 42 };    
    
    // Je nach Kontext Bar.h
    static const stDef BarDef = { 123 };
    
    // Je nach Kontext BarFoo.h
    static const stDef definitions[2] = { FooDef, BarDef };
    

    Edit: Habe gelöschten Beitrag wiederhergestellt.



  • @SoIntMan sagte in partieller Code (include *.c file) schlechter Stil?:

    dadurch dass nur die die pool.c bar/foo kennt/verwendet .. dachte ich mir ich kann mirfoo.h/bar.h sparen da ich ja direct c includieren kann..

    Wenn static nur zum "ruhigstellen" war und die Sichtbarkeit hier nicht wichtig ist, dann kannst du dir in dem Fall die Header auch sparen, indem du deren Inhalt (die Deklarationen von part_Foo und part_Bar) direkt in die pool.c schreibst:

    // pool.h
    typedef struct stDef 
    {
      int someinfo;
    } stDef ;
    
    stDef getDef(const int id);
    
    //pool.c
    #include <pool.h>
    
    stDef part_Foo();
    stDef part_Bar();
    
    stDef getDef(const int id)
    {
        static stDef definitions[2] = {0};
        definitions[0] = part_Foo();
        definitions[1] = part_Bar();
        return definitions[id];
    }
    
    // def.c oder alternativ eine foo.c und eine bar.c.
    #include <pool.h>
    
    stDef part_Foo()
    {
        stDef def = { 42 };
        return def;
    }
    
    stDef part_Bar()
    {
        stDef def = { 123 };
        return def;
    }
    

    Das ist Äquivalent zur Lösung mit den 2 Headern, nur eben ohne die 2 extra Dateien. Das würde ich für so etwas simples auch in der Form bevorzugen. Zu viele Dateien können ein Projekt auch unübersichtlich machen.

    Oder alternativ auch ohne Funktionen und direkt mit globalen Variablen:

    //pool.c
    #include <pool.h>
    
    extern stDef myproject_foo_def;
    extern stDef myproject_bar_def;
    
    stDef getDef(const int id)
    {
        static stDef definitions[2] = {0};
        definitions[0] = myproject_foo_def;
        definitions[1] = myproject_bar_def;
        return definitions[id];
    }
    
    // def.c oder alternativ eine foo.c und eine bar.c.
    #include <pool.h>
    
    const stDef myproject_foo_def = { 42 };
    const stDef myproject_bar_def = { 123 };
    

    Die sind dann in der Form zumindest nicht für jeden sichtbar, der pool.h einbindet.
    Probleme mit Initialisierungsreihenfolge natürlich erstmal außen vor. Mit den Variablen sollte man getDef natürlich erst aufrufen, wenn die globalen Konstruktoren durch sind (im Zweifel frühestens ab der main()). Ansonsten machen die Funktionen mehr Sinn.


  • Mod

    @Quiche-Lorraine : Ich weiß nicht, wieso du es gelöscht hast, aber ich erinnere mich noch was da stand (und ich kann meine Moderatorenfähigkeiten einsetzen, um die Geschichte zu sehen 😉 ), aber ich kann dir als Feedback geben, dass das eigentlich ein solider Vorschlag war.



  • @Finnegan sagte in partieller Code (include *.c file) schlechter Stil?:

    Oder alternativ auch ohne Funktionen und direkt mit globalen Variablen:

    hmm.. das ist auch noch ne gute idee. das stimmt..

    @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    Wenn das natürlich nur vereinfachter Beispielcode ist, und da irgendwelche Pointer eine Rolle spielen, dann ist das const natürlich wichtig. Dann aber um so mehr Vorsicht mit den statics, ob die Objekte, auf die du zeigst, auch wirklich existieren.

    ja statisch objekte in c files sind ja dann nur in der c bekannt.. ich kann dann in diversen c files den selben namen der variablen nehmen oder nicht.. und was meinst du mit ob die objekte auch wirklich existieren? vll. habe ich dich auch falsch verstanden..

    @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    machen, egal ob da nun int x() oder const int x() stünde.

    du meinst weil es in c keine referencen gibt.. dass da const egal is? guter hinweiß...

    @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    @Quiche-Lorraine : Ich weiß nicht, wieso du es gelöscht hast, aber ich erinnere mich noch was da stand (und ich kann meine Moderatorenfähigkeiten einsetzen, um die Geschichte zu sehen ), aber ich kann dir als Feedback geben, dass das eigentlich ein solider Vorschlag war.

    ja bin offen für vorschläge, nur raus damit



  • @SeppJ
    Ich war gerade ein wenig verwirrt, da ich es nur mit C++ Mitteln getestet habe.

    Aber danke für deinen Hinweis, ich habe ihn wiederhergestellt.



  • @Quiche-Lorraine sagte in partieller Code (include *.c file) schlechter Stil?:

    Mal eine dumme Frage. Was spricht gegen:
    typedef struct stDef
    {
    int someinfo;
    } stDef ;

    // Je nach Kontext Foo.h
    static const stDef FooDef = { 42 };

    // Je nach Kontext Bar.h
    static const stDef BarDef = { 123 };

    // Je nach Kontext BarFoo.h
    static const stDef definitions[2] = { FooDef, BarDef };

    servus, das ist ein genialer ansatz, den hatte ich anfangs auch im kopf 🙂 ABER. die zeile

    static const stDef definitions[2] = { FooDef, BarDef };
    

    schmeist in VSC 14 eien compilerfehler.. dass bei FooDef ,BarDef ein konstanter austruck erwartet wird, was er auch laut code ist.. aber vsc streikt ..gcc geht.. 😉



  • @SoIntMan

    #pragma once
    
    typedef struct stDef
    {
    	int someinfo;
    } stDef;
    
    // Je nach Kontext Foo.h
    //static const stDef FooDef = { 42 };
    
    #define FooDef() { 42 }
    
    // Je nach Kontext Bar.h
    //static const stDef BarDef = { 123 };
    
    #define BarDef() { 123 }
    
    // Je nach Kontext BarFoo.h
    static const stDef definitions[2] = { FooDef(), BarDef() };
    

    So funktioniert es. Nicht schön aber selten.

    Und irgentwie vermisse ich hier schon C++ wg. constexpr,...

    Du siehst ja aich direkt das Problem. Die Defines sind nicht typsicher.



  • Das hatte ich für @SoIntMan schon vor 1,5 Monaten in statische komplexe objekte initialisieren Frage/Problem herausgefunden.



  • @Th69 sagte in partieller Code (include *.c file) schlechter Stil?:

    Das hatte ich für @SoIntMan schon vor 1,5 Monaten in statische komplexe objekte initialisieren Frage/Problem herausgefunden.

    ja richtig, war aber nicht direkt das Thema...

    @Quiche-Lorraine sagte in partieller Code (include *.c file) schlechter Stil?:

    @SoIntMan
    #pragma once

    typedef struct stDef
    {
    int someinfo;
    } stDef;

    // Je nach Kontext Foo.h
    //static const stDef FooDef = { 42 };

    #define FooDef() { 42 }

    // Je nach Kontext Bar.h
    //static const stDef BarDef = { 123 };

    #define BarDef() { 123 }

    // Je nach Kontext BarFoo.h
    static const stDef definitions[2] = { FooDef(), BarDef() };

    So funktioniert es. Nicht schön aber selten.
    Und irgentwie vermisse ich hier schon C++ wg. constexpr,...
    Du siehst ja aich direkt das Problem. Die Defines sind nicht typsicher.

    netter workaround, aber gefällt mir nicht so.. muss ich mal sacken lassen


  • Mod

    @SoIntMan sagte in partieller Code (include *.c file) schlechter Stil?:

    ja statisch objekte in c files sind ja dann nur in der c bekannt.. ich kann dann in diversen c files den selben namen der variablen nehmen oder nicht.. und was meinst du mit ob die objekte auch wirklich existieren? vll. habe ich dich auch falsch verstanden..

    Ich dachte da dran, dass die Objekte durch zu viele statics an den falschen Stellen ggf. häufiger existieren als nur einmal. Falls das nur dumme Konstanten sind, ist das kein Problem. Wenn das aber Singleton-artige Objekte sind, die einen veränderlichen Zustand tragen, dann würdest du Probleme bekommen.



  • @SeppJ sagte in partieller Code (include *.c file) schlechter Stil?:

    Ich dachte da dran, dass die Objekte durch zu viele statics an den falschen Stellen ggf. häufiger existieren als nur einmal. Falls das nur dumme Konstanten sind, ist das kein Problem. Wenn das aber Singleton-artige Objekte sind, die einen veränderlichen Zustand tragen, dann würdest du Probleme bekommen.

    ne das sind wirklich nur readonly daten. ich bin kein fan von static absolut nicht.. vewendet hier nur static damit die daten nur in c-file sichtbar sind und "einmal" um die Def Array zu initalisieren



  • @SoIntMan sagte in partieller Code (include *.c file) schlechter Stil?:

    @Th69 sagte in partieller Code (include *.c file) schlechter Stil?:

    Das hatte ich für @SoIntMan schon vor 1,5 Monaten in statische komplexe objekte initialisieren Frage/Problem herausgefunden.

    ja richtig, war aber nicht direkt das Thema...

    @Quiche-Lorraine sagte in partieller Code (include *.c file) schlechter Stil?:

    @SoIntMan
    #pragma once

    typedef struct stDef
    {
    int someinfo;
    } stDef;

    // Je nach Kontext Foo.h
    //static const stDef FooDef = { 42 };

    #define FooDef() { 42 }

    // Je nach Kontext Bar.h
    //static const stDef BarDef = { 123 };

    #define BarDef() { 123 }

    // Je nach Kontext BarFoo.h
    static const stDef definitions[2] = { FooDef(), BarDef() };

    So funktioniert es. Nicht schön aber selten.
    Und irgentwie vermisse ich hier schon C++ wg. constexpr,...
    Du siehst ja aich direkt das Problem. Die Defines sind nicht typsicher.

    netter workaround, aber gefällt mir nicht so.. muss ich mal sacken lassen

    Das ist doch genau das, was ich auch mit den Makros gemacht habe (nur hier als Funktionsmakros - warum eigentlich?).

    Und das Problem bei deinem Code

    stDef getDef(const int id)
    {
        static stDef definitions[2] = {0};
        definitions[0] = myproject_foo_def;
        definitions[1] = myproject_bar_def;
        return definitions[id];
    }
    

    ist, daß zwar definitions statisch ist, bei jedem Aufruf aber die einzelnen Zuweisungen jeweils ausgeführt werden (d.h. die Daten kopiert werden) -> das kann doch nicht wirklich dein Ziel sein...



  • @Th69 sagte in partieller Code (include *.c file) schlechter Stil?:

    Das ist doch genau das, was ich auch mit den Makros gemacht habe (nur hier als Funktionsmakros - warum eigentlich?).

    absolut, da stimmt.

    @Th69 sagte in partieller Code (include *.c file) schlechter Stil?:

    ist, daß zwar definitions statisch ist, bei jedem Aufruf aber die einzelnen Zuweisungen jeweils ausgeführt werden (d.h. die Daten kopiert werden) -> das kann doch nicht wirklich dein Ziel sein...

    ja da hast du auch recht, aus der sichtweiße dann doch mit makros. die aufrufw finden nur selten statt, aber ich geb dir recht;)


Anmelden zum Antworten