Werbung

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

Union-Magic

Variablen konsekutiv in den Speicher zwingen

  1. -AB-
    Hallo Forum!

    Trotz des abenteuerlichen Titels geht es eigentlich nur um eine Kleinigkeit, zu der ich aber damals recht wenig im Internet gefunden habe.
    Es geht darum, dass Variablen, in diesem Fall insbesondere Membervariablen, nicht konsekutiv im Speicher liegen müssen, Stichwort alignment. Sprich, wenn ich eine Klasse

    Code (C++):
    Quelltext kopieren
    1. struct Vec
    2. {
    3.     float x;
    4.     float y;
    5.     float z;
    6. }
    habe, garantiert mir niemand, dass (&x)++ z.B. auf y zeigt.

    Graben wir einmal in der C-Kiste, oh schau, eine union. Damit kann man allerlei Unfug anstellen:
    Code (C++):
    Quelltext kopieren
    1.  
    2. struct Vec
    3. {
    4.     union
    5.     {
    6.         float data[3];
    7.         struct
    8.         {
    9.             float x;
    10.             float y;
    11.             float z;
    12.         };
    13.     };
    14. }
    15.  
    Zwar sind unbenannte unions meines Wissens nach nonstandard, werden aber mindestens von GCC/VisualStudio unterstützt.

    Auf diese Weise wird sichergestellt, dass die drei float-Variablen hintereinander im Speicher liegen. Ob der Compiler das sauber erledigt, kann man sogar mit einem sizeof(union) vs sizeof(float[3]) testen.
    Jetzt kann man wie folgt....
    Code (C++):
    Quelltext kopieren
    1. Vec vec;
    2.  
    3. vec.x += 15;
    4.  
    5. for(unsigned i = 0; i<3;++i)
    6.     vec.data[i] = i*2;
    ...auf die Daten zugreifen. Für template-Metaprogrammierung ist das hin und wieder extrem sinnvoll, da man so relativ einfach eine Schleife schreiben kann, die z.B. die Länge beliebigdimensionaler Vektoren ausrechnen kann, ohne dabei die unterliegende Struktur der Vektor-Klassen zu ändern, bzw, ohne auf den Komfort beim Zugriff mittels .x, .y zu verzichten.
    Man kann die union völlig problemlos mit templates nutzen, so brauchte ich z.B. Zugriff auf die ersten n Bits eines Hashwertes:
    Code (C++):
    Quelltext kopieren
    1. template <typename DataType=unsigned long long, unsigned int IndexBitSize=20>
    2. struct Hash
    3. {
    4.     union
    5.     {
    6.        DataType hashValue;
    7.        DataType hashIndex : IndexBitSize;
    8.     };
    9. };
    Anstatt mit Bitmasken herumzurechnen, kann man auf diese Weise per hashIndex auf die ersten 20 Bits direkt zugreifen, weil beide Variablen im selben Speicherbereich liegen. Auch, wenn ich den hashIndex nur als int oder short haben möchte.

    Letztes Beispiel:
    ein const int data[3]; lässt sich nicht sinnvoll als Member nutzen, da ich (zumindest prä-C++0x) data nicht in der Memberinitialisierungsliste zuweisen kann. Mit dem Trick von oben kann ich aber x, y und z initialisieren - was letztendlich genau das tut, was ich möchte:

    Code (C++):
    Quelltext kopieren
    1. struct ConstVec
    2. {
    3.    ConstVec(float a, float b, float c) : data(), x(a), y(b), z(c)
    4.    {}
    5.  
    6.    union
    7.    {
    8.       const float data[3];
    9.       struct
    10.       {
    11.          const float x;
    12.          const float y;
    13.          const float z;
    14.       };
    15.    };
    16. };
    Die Chancen stehen gut, dass es nächstes mal um Funktoren und/oder Metaprogrammierung geht :) Wie immer sind Anmerkungen aller Art gern willkommen.

Letzte Rezensionen

  1. lano
    lano
    5/5,
    Was soll ich schreiben? Super Sache son union.