Frage betreffend Union



  • OK, danke!
    Aber warum kommt als Ergebnis ausgerechnet 232 und 29 raus?
    Wenn es der gleiche Speicherbereich ist, müsste doch einfach ein gewisser Teil vom Speicherbereich von "word" ausgegeben werden?


  • Mod

    Dieser Code gibt dir das erste und das zweite Byte einer zwei chars umfassenden short Variable aus. Dieses Verhalten ist in vielerlei Hinsicht undefiniert, wird aber auf vielen Systemen funktionieren, zumindest auf denen, wo sizeof(short)=2 ist und die shorts im Big-endian Format abspeichern.

    Ich nehme mal an, wenn du nach unions fragst, dann hast du dich zumindest ein bisschen mit dem Thema beschäftigt und weißt, was sie machen. Das werde ich hier nämlich nicht erklären.

    Dies ist die Idee des Programmierers: Zuerst speichert das Programm einen short Wert in der union als Wandler.word. Vorausgesetzt, sizeof(short)=2 und Big-Endian für shorts, steht im Speicher dann sowas:

    --------------------------------------------------
    | Erster Teil von Word  | Zweiter Teil von Word  |
    --------------------------------------------------
    
    |                Wandler.Word                    |
    |-----------------  Wandler ---------------------|
    

    Da es sich um eine union handelt, kann der gleiche Speicher aber auch so angesprochen werden:

    --------------------------------------------------
    |    Wandler.hi         |     Wandler.lo         |
    --------------------------------------------------
    
    |-----------------  Wandler ---------------------|
    

    Und so kann man zwei chars aus dem short Wert erhalten.

    Nun die Probleme:
    1. Der Standard sagt explizit, dass das Verhalten von unions nur definiert ist, wenn man wieder das gleiche Element liest, dass man vorher gespeichert hat. Also eigentlich dürfte das Programm nach dem Speichern des shorts die union nur als short ansprechen, wenn das Verhalten definiert sein soll. Dass es trotzdem funktioniert liegt daran, dass praktisch alle Compiler unions so implementieren wie oben erklärt. Sie brauchen es aber nicht zwangsläufig so zu machen.
    2. Es werden allerlei Annahmen gemacht, die nicht unbedingt erfüllt sind. Weder sizeof(short)=2 noch das Format in dem ein short im Speicher liegt sind definiert.

    Die Verwendung von unions ist eher ungewöhnlich, sie sind eigentlich ein Relikt aus Speichersparzeiten. Denn eigentlich sind sie dazu gut, Variablen platzsparend zu speichern. Die Verwendung wie hier ist ziemlich unsauber, wie schon erläutert. Man könnte genausogut einen reinterpret_cast machen. Oder besser noch: Rechnen. Denn dann ist man auf der sicheren Seite.



  • Okay, vielen Dank euch für die ausführliche Erklärung!
    So wie ich das sehe sollten also Unions eigentlich nicht mehr verwendet werden, aber es ist natürlich trotzdem praktisch zu wissen wie sie funktionieren - und jetzt ist alles klar! 😉


  • Mod

    Miness schrieb:

    Okay, vielen Dank euch für die ausführliche Erklärung!
    So wie ich das sehe sollten also Unions eigentlich nicht mehr verwendet werden, aber es ist natürlich trotzdem praktisch zu wissen wie sie funktionieren - und jetzt ist alles klar! 😉

    Es kann schon Sinn machen, du solltest sie nicht aus Prinzip nicht verwenden. Nur ist es halt relativ selten, dass man sie zu ihrem eigentlichen Einsatzzweck braucht.

    Den Missbrauch wie in deinem Beispiel, sollte man aber vermeiden.



  • SeppJ schrieb:

    Es kann schon Sinn machen, du solltest sie nicht aus Prinzip nicht verwenden. Nur ist es halt relativ selten, dass man sie zu ihrem eigentlichen Einsatzzweck braucht.

    Den Missbrauch wie in deinem Beispiel, sollte man aber vermeiden.

    Klar, aus Prinzip nicht verwenden ist immer schlecht. Aber kannst du mir ein konkretes Beispiel für den Einsatzzweck nennen? Ich sehe dahinter im Moment noch nicht wirklich einen Sinn (ausser zum Sparen von Speicherplatz).



  • Small String Optimization.



  • volkard schrieb:

    Small String Optimization.

    Sorry für die Frage, aber was ist das? 😉



  • Miness schrieb:

    Okay, vielen Dank euch für die ausführliche Erklärung!
    So wie ich das sehe sollten also Unions eigentlich nicht mehr verwendet werden

    "Nicht verwenden" stimmt nicht. Du kannt nur nicht, bezogen auf obiges Beispiel, darauf schliessen was in "word" steht, wenn Du "byte" beschrieben hast und umgekehrt. In einer Union ist nur das zuletzt beschriebene Element gültig. Zum Zerlegen eines 2-Byte Wertes in einzelne Bytes sind Unions nicht geeignet. Dazu nimm lieber Shift-Operatoren.



  • Laß einen String drei Zeiger schwer sein, begin, end und maxEnd (weil mehr SPeicgher angelegt sein könnte, als gerade benutzt wird). 12 Bytes.
    Dann kann man sich gleich auch den Luxus gönnen und 16 Bytes nehmen und die ersten vier Bytes zeigen den echten typ des Strings an, einer der Untertypen ist der Kurz-String, der hat in den anderen 12 Bytes gleich die Nutzdaten.

    class String{
       virtual ~String();//die ersten 4 Bytes
       union{
          struct{//normal mit new angelegt
            char* begin;
            char* end;
            char* maxEnd;
          }
          struct{//kleiner string
            char length;
            char data[11];
          }
          struct{//literal
            char* begin;
            char* end;
          }
       }
    


  • Z schrieb:

    "Nicht verwenden" stimmt nicht. Du kannt nur nicht, bezogen auf obiges Beispiel, darauf schliessen was in "word" steht, wenn Du "byte" beschrieben hast und umgekehrt. In einer Union ist nur das zuletzt beschriebene Element gültig. Zum Zerlegen eines 2-Byte Wertes in einzelne Bytes sind Unions nicht geeignet. Dazu nimm lieber Shift-Operatoren.

    Sehe ich das richtig, dass Shift-Operatoren bitweise kopieren können?


  • Mod

    Miness schrieb:

    Z schrieb:

    "Nicht verwenden" stimmt nicht. Du kannt nur nicht, bezogen auf obiges Beispiel, darauf schliessen was in "word" steht, wenn Du "byte" beschrieben hast und umgekehrt. In einer Union ist nur das zuletzt beschriebene Element gültig. Zum Zerlegen eines 2-Byte Wertes in einzelne Bytes sind Unions nicht geeignet. Dazu nimm lieber Shift-Operatoren.

    Sehe ich das richtig, dass Shift-Operatoren bitweise kopieren können?

    Nein, die rechnen bloß. Das sieht dann aber so aus, als hätten sie bitweise kopiert.



  • Einen Sinn machen Unions auch wenn man mit Streams irgend einer Art arbeitet und es bevorzugt wenn zwar unterschiedliche Datentypen verschickt werden, diese aber der Einfachheit halbe immer die gleiche Länge haben sollen. Sieht dann in etwa so aus:

    struct tMessage{
      tMessageTyp type;
      union{
        tLargeMessage large;
        tShortMessage short;
        tWhateverMessage whatever;
        int nureinint;
        tUndSoweiter undsoweiter;
      };
    };
    

Anmelden zum Antworten