Problem mit union



  • hermes schrieb:

    Klar habe ich den Sinn einer Union verstanden.
    Wenn ich die Membervariable TxData.Values.SN beschreibe wird der Wert
    gleichzeitig nach TxData.Buffer.TXBuffer gespeichert, da die Start Adressen
    der beiden structs an der gleichen Speicherstelle liegen.
    Weiter Mebervariablen der Structure Values werden ebenfalls an die entsprechende
    Position nach TXBuffer geschrieben.

    Tja, weit gefehlt. Eine Union ist dazu da, Speicher zu sparen. Man soll bei einer union nur auf das zuletzt zugewiesene Feld zugreifen. Zugriff auf die anderen Felder ist nicht durch den Standard definiert.
    Der Standard greift einem hier aber zumindest soweit unter die Arme, dass Unions im C-Speicherlayout vorliegen. Sofern dir klar ist, welche Bitmuster du mit der Zuweisung auf ein Union-Element erzeugst, ist das alles für deine Plattform und deinen Compiler in der aktuellen Version definiert (sofern du dich wiederum an das C-Speicherlayout hältst). Ich hoffe dir ist klar, dass der letzte Part eine äußerst brüchige und unportable Angelegenheit ist und deshalb nicht verwendet werden sollte. Anderenfalls kommt es einem reinterpret_cast gleich - mit dem Unterschied, dass du den cast nichtmal mehr hinschreibst. Das nennt sich dann Type-Punting (das Typ-System wird in die Tonne getreten). Sollte man also nur wirklich da anwenden, wo low-level-APIs das von dir erfordern.
    Und immer daran denken: "If you lie to the compiler, it will get its revenge (for sure)."



  • Weil du ihn doppelt verwendet hast - einmal als typedef für "unsigned char[50]" und einmal als Element der Union.

    Sehe ich ein.

    union 
    {
           struct
           {
                unsigned int a;
                unsigned int b;
           }Values;
    
           struct
           {
                unsigned char TXBuffer[50];
    
           }Buffer;         
    }TxData;
    
    TXData.Values.a = 0x1234;
    TXData.Values.b = 0x5678;
    

    Nun steht in TXData.Buffer.TXBuffer[0] = 34, [1] = 12, [2] = 78, [3] = 56.
    Denn Bufferinhalt sende ich nun via Rs232 zu einem Controller, der folgende
    union hat

    union 
    {
           struct
           {
                unsigned int a;
                unsigned int b;
           }Values;
    
           struct
           {
                unsigned char RXBuffer[50];
    
           }Buffer;         
    }RxData;
    

    nach RxData.Buffer.RxBuffer .

    Nun stehen in RxData.Values.a = 0x1234 , ...b = 5678.
    Ich erspare mir damit das lästige umkopieren der Values in die Buffer.



  • Und an welcher Stelle hast du nun deine Probleme? Am Ende steht das in den Rx... Elementen, was du vorne in Tx... eingetragen hast.

    (btw kannst du Probleme bekommen, wenn du beide Teile auf verschiedenen Systemen laufen hast - der C++ Standard schreibt nicht vor, wie (z.B.) ein unsigned int aufgebaut ist)

    PS: Was ich noch verbessern würde: gib der union einen Namen und pack sie in einen gemeinsam verwendeten Header 😉

    //defs.h
    union MsgData
    {
      //...
    };
    
    //Tx.cpp
    #include "defs.h"
    MsgData TxData;
    
    //Rx.cpp
    #include "defs.h"
    MsgData RxData;
    


  • typedef unsigned char BUFFER[50];
    typedef union
    {
        struct
        {
              unsigned char ClearTestStatus        :1;  // 1 Done
        }bits;
        unsigned char byte;
    
    }RESETTESTMODE;
    union
    {
        struct
        {
                     unsigned int          SN;
                     unsigned int          Dummy;   //Hier muss ich ein Dummy          
            RESETTESTMODE ResetTestMode;     //einfügen
        }Values;
         struct
         {
                BUFFER TXBuffer;
        }Buffer;
    }TxData;
    

    Das mit dem BUFFER sollte so ausehen.



  • Und wo ist das Problem? in der Union stehen "parallel" zueinander eine struct mit drei Elementen (das letzte ist wieder eine union) und dein char-Buffer - wobei die Verteilung der struct-Bytes in den Puffer-Bereich willkürlich vom Compiler/Prozessor/was-weiß-ich vorgenommen werden kann.



  • (btw kannst du Probleme bekommen, wenn du beide Teile auf verschiedenen Systemen laufen hast - der C++ Standard schreibt nicht vor, wie (z.B.) ein unsigned int aufgebaut ist)

    Da das eine auf dem PC 80x86 läuft ist hier ein int natürlich 32 bit breit, es muss
    natürlich unsigned short(16Bit) sein, ein Schreibfehler von mir,

    union
    {
           struct
           {
                unsigned short a;
                unsigned short b;
           }Values;
    
           struct
           {
                unsigned char TXBuffer[50];
    
           }Buffer;        
    }TxData;
    
    TXData.Values.a = 0x1234;
    TXData.Values.b = 0x5678;
    

    Da die zweite Union sich in einem 8Bit Controller
    befindet

    union
    {
           struct
           {
                unsigned int a;
                unsigned int b;
           }Values;
    
           struct
           {
                unsigned char RXBuffer[50];
    
           }Buffer;        
    }RxData;
    

    ist hier int natürlich 16bit breit.

    wobei die Verteilung der struct-Bytes in den Puffer-Bereich willkürlich vom Compiler/Prozessor/was-weiß-ich vorgenommen werden kann.

    Wie mir bekann ist stehen die MemberVariablen in einer struct immer der
    Reihe nach im speicher.
    Ich habe diese frage schon einmal gestellt, es wurde behauptet das dieses
    bei jedem Compiler so ist.
    Na ja bei dem C++ Bilder sowie den Compiler für den µC ist es jedenfalls
    so(im Watch Fenster überprüft).

    Auf jedenfall funktioniert das ganze so wie ich es gemacht habe.



  • Die Elemente stehen hintereinander im Speicher - aber dazu kommen noch Probleme wie Padding (der Compiler darf Zwischenräume lassen) und big endian vs little endian (Bedeutung der Bits in einem int).



  • Ok, also für mich war(ist) eine Union für meinen Zweck bestens geeigned.
    Da es aufgrund dieser Tatsache nicht auf jedem Compiler so läuft, frage
    ich mich wofür dann so eine Union da ist.

    Gebe mal ein praktisches Beispiel.



  • hermes schrieb:

    Da es aufgrund dieser Tatsache nicht auf jedem Compiler so läuft, frage
    ich mich wofür dann so eine Union da ist.

    Meinen Post gelesen? 😉



  • Eine Union ist dazu da, Speicher zu sparen. Man soll bei einer union nur auf das ??? zuletzt zugewiesene Feld zugreifen.?????

    Verstehe ich nicht ganz, kannst du das mal genauer erklären.



  • Eine besondere Typkonstruktion ist die union. Man könnte sie als Entweder-oder-Verbund bezeichnen. In einer Union werden mehrere Variablen zusammengefasst, von denen nur eine gebraucht wird. Es kann also immer nur eines der angegebenen Elemente verwendet werden. Eine Union nimmt darum so viel Speicher ein, wie das größte seiner Elemente benötigt.

    Ok ist schon klar, hast du nicht einen Vorschlag wie man das was ich möchte
    anders hinbekommt?


Anmelden zum Antworten