Structs über Templates bearbeiten



  • Hi,

    die Ausgangssituation ist immer die, dass ich ein unsigned char* bekomme und daraus die Daten für die Structs lesen muss. Die Länge ist zusätzlich bekannt.

    Leider kann ich das nicht so machen:

    unsigned char *pcData; //die Daten
    TMyStruct *pMyStruct = (TMyStruct*) pcData; //ich weiss, wird nicht gern gesehen
    

    da das Ganze in big-endian vorliegt.

    Für das Auslesen der einzelnen Werte des Structs hab ich mir schon ein Template geschrieben.

    Doch wie kann ich das jetzt für verschiedenste Structs (die Member variieren von unsigned short, unsigned int, unsigned char, unsigned char[]) machen? Irgendwie bin ich fast der Meinung, dass das nicht möglich ist.
    Hat jmd schon mal so was umgesetzt?

    Maffe



  • Was soll das bitteschön werden? Aus deiner Beschreibung werde ich nicht ganz schlau.

    (am besten verpasst du jedem deiner Strukturtypen einen char*-Konstruktor, der den übergebenen String dann geeignet auseinandernimmt)



  • Hmm,

    hab ich mich so undeutlich ausgedrückt?

    Bsp:

    TMyStruct1
    {
        unsigned char Val1;
        unsigned short Val2;
        unsigned char Text1[10];
        unsigned int Val3;
    };
    
    TMyStruct2
    {
        unsigned short Val1;
        unsigned short Val2;
        unsigned int Val3;
    };
    

    Wie sollte das Template aussehen, um jetzt die Daten aus dem unsigned char* auszulesen? Die Identifikation, welche Daten enthalten sind, bekomme ich aus dem Header im Array. Also kann ich das Template auch explizit benutzen.



  • Vielleicht ist meine Idee mit dem Templates auch nicht die Beste? Fällt euch denn eine andere Möglichkeit ein, wie man mein Problem lösen kann, ohne dass ich für jedes Struct eine eigene Funktion schreiben muss?



  • Bei Templates mußt du zur Compilezeit wissen, mit welchem Typ du die instantiieren mußt - von daher fallen sie für Laufzeit-Überprüfungen aus.

    (interessant wäre es ja zu wissen, nach welchen Kriterien du zwischen TMyStruct1 und TMyStrunct2 auswählst)

    PS: Eventuell wäre ein "virtueller Konstruktor" etwas für dich.



  • @CStoll:

    Ich hab deine erste Idee aufgegriffen. Jedes Struct bietet jetzt die gleichen Funktionen an, so dass die Bearbeitung über ein Template kein Problem mehr ist.

    Danke nochmal. 🙂

    [EDIT]Rechtschreibfehler :D[/EDIT]



  • Maffe001 schrieb:

    die Ausgangssituation ist immer die, dass ich ein unsigned char* bekomme und daraus die Daten für die Structs lesen muss. Die Länge ist zusätzlich bekannt.

    Leider kann ich das nicht so machen:

    unsigned char *pcData; //die Daten
    TMyStruct *pMyStruct = (TMyStruct*) pcData; //ich weiss, wird nicht gern gesehen
    

    da das Ganze in big-endian vorliegt.

    Für das Auslesen der einzelnen Werte des Structs hab ich mir schon ein Template geschrieben.

    Doch wie kann ich das jetzt für verschiedenste Structs (die Member variieren von unsigned short, unsigned int, unsigned char, unsigned char[]) machen? Irgendwie bin ich fast der Meinung, dass das nicht möglich ist.
    Hat jmd schon mal so was umgesetzt?

    Ja, sogar schon öfter. Die Lösung ist immer ein binärer Stream. Du baust Dir eine eigene Stream-Klasse, die von std::basic_ios< char > abgeleitet ist, und implementierst für die einzelnen rudimentären Typen (char, int, long, usw ) die operator>>( Type& x )-Methoden. In eben diesen Methoden kannst Du dann alle Big- und little-Endian-Probleme erledigen.
    Danach brauchst Du noch einen streambuf, auf dem der Stream arbeiten kann. Ein Memory-Streambuf zu machen ist sehr einfach - z.B.:

    #include <streambuf>
    
    class MemoryBuf : public std::streambuf
    {
    public:
        typedef std::streambuf base_type;
    
        MemoryBuf( char* first, char* last )
            : base_type()
        {
            setg( first, first, last );
        }
    };
    

    den legst Du an, übergibst Anfang und Ende Deines char-Arrays, und anschließend legst Du Deinen Stream an und übergibst einen Pointer auf eben diesen MemoryBuf. Besser wäre es noch, Du baust (oder hast) einen Streambuf für Deine Original-Zeichen-Strom-Quelle (z.B. File,Socket, etc. )

    Dann muss man leider für jede struct einen operator>> schreiben

    DeinStream& operator>>( DeinStream& in, EineStruct& s );
    

    in der dann die einzelnen Member der Struct eingelesen werden. Wenn Du das für zu viel Arbeit und für zu kompliziert hälst, dann lass Dir sagen: es gibt in C++ keine einfachere Lösung, die Dir ein solches Maß an Problem-Behandlung und Flexibilität liefert. Im übrigen ist das auch noch ziemlich Standard-like 🕶

    Gruß
    Werner


Anmelden zum Antworten