struct global nutzen / neu deklarieren

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hey,

    ich hab ein Problem in C, ich bin mir nicht sicher ob das überhaupt so machbar ist wie ich mir das vorstelle.

    Ich habe eine Library die von verschiedenen Geräten importiert wird. In dieser soll ein globaler struct existieren, der allerdings für jedes Gerät/Anwendungsfall unterschiedliche Inhalte haben soll, also auch eine unterschiedliche Anzahl an Einträgen, unterschiedliche Typen usw. Das heißt dieser struct sollte quasi in den device-spezifischen "treibern" erst mit Inhalten/Deklarationen gefüllt werden.
    Prinzipiell also eine als extern deklarierte "struct-Variable". Ist so etwas irgendwie möglich? Das Problem derzeit ist dass er natürlich den Typ des structs nicht kennt, da der ja erst in den treibern deklariert wird.

    Code
    extern structdefinition name; // funktioniert nicht, da structdefinition erst in den Treibern
    // vorher:
    typedef struct structdefinition name; // funktioniert auch nicht wirklich, da der Compiler dann natürlich wegen redefinition meckert

    Ich möchte NICHT:
    - die Treiber in die Library inkludieren, wäre ja sinnlos dann
    - in der Library unterscheiden welches Gerät sie gerade nutzt (das wäre die Notfall-Variante, aber das muss doch auch anders gehen?!)
    edit: Möchte auch nicht jeder Funktion in der Library einen Pointer auf den struct übergeben müssen

    Ich hoffe ich habe mich klar ausgedrückt, sonst einfach nachfragen.
    Vielen Dank schonmal.


    MfG xlemmingx

    Einmal editiert, zuletzt von xlemmingx (24. Oktober 2013 um 11:03)

  • Ein Pointer ist hier die Lösung. Er kann ja in deiner library global sein, wenn du ihn nicht übergeben willst.

    Ich vermute mal, dass die Struktur gemeinsame Teile beinhaltet (mit denen die library arbeitet) und spezifische Teile, die nur der jeweilige Treiber nutzt. Das geht, wenn du alle gemeinsamen struct - member am Anfang des structs definierst. Dahinter können dann spezifische member folgen. Du definierst dann in der Lib einen struct, der nur die allgemeinen member enthält. Von diesem Typ legst du dann einen Pointer an, den du mit einem (auf deinen Basis-struct gecasteten) Pointer auf den tatsächlichen struct des Treibers initialisiert.

  • Moin,

    ich denke, die Lösung dürfte "union" heissen ...
    Etwa so in der Art:


    Falls noch was unklar ist, fragen ;) ...

    cheers,
    -ds-

  • Die Union löst aber die Probleme nicht:

    • Wenn sie in der Library angelegt wird, muss die Library jeden Treiber "kennen", damit dessen struct Teil der union werden kann.
    • Nicht alle Compiler unterstützen den anonymen "Durchgriff" in die einzelnen structs, da dies nicht C-Standard-konform ist. Also muss die Library die Elemente der structs mit vollem Namen ansprechen, wodurch sie wieder eine Fallunterscheidung für alle einzelnen Treiber machen muss.


    Für das ursprüngliche Problem (Code arbeitet mit einer Abstraktion von Daten, nicht mit deren konkreten Ausprägung) gibt es in objektorientierten Sprachen das Konzept der Vererbung: Die Treiber werden als Klassen implementiert, die alle von einer gemeinsamen Basisklasse abgeleitet werden. Die Library arbeitet ausschließlich mit den Methoden und Daten der Basisklasse, während die Treiber diese beliebig erweitern und an ihre konkrete Implementierung anpassen können.

    Dieses Konzept kannst du in C nachbilden. Dazu wurde im C-Standard extra die Eigenschaft definiert, dass Strukturen, die mit gleichen Elementen beginnen, vom Compiler immer gleich angelegt werden müssen. Damit werden sie kompatibel im Sinne einer Basisklasse:

    Die Library ist somit total unabhängig von den Treibern und kann auch mit noch gar nicht existierenden Treibern zusammenarbeiten, solange diese sich später an die vereinbarte Schnittstelle halten. Wie von dreamshader beschrieben, kann man sogar Funktionen im Treiber aufrufen, wenn man diese als Funktionspointer in der Struktur ablegt. Die Treiber können die Struktur darüber hinaus beliebig erweitern. Natürlich kann die Library mit diesen Erweiterungen nicht umgehen.

    Wenn du diesen Ansatz umsetzt, solltest du übrigens trotzdem darüber nachdenken, jeder Funktion den Treiber-Pointer zu übergeben. Dadurch könnte die Library später sogar gleichzeitig mit mehreren Treibern umgehen.

    Einmal editiert, zuletzt von Singletrailer (24. Oktober 2013 um 20:23)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!