unions und der liebe Standard



  • Hi,

    union V
    {
      float data[4];
      struct 
      {
        float x, y, z, w;
      };
    };
    

    Wird hier garantiert, dass die Daten genau übereinanderliegen, also dass x == data[0], ...?
    Falls nicht, habt ihr schon mal irgendeinen Compiler gesehen, bei dem das nicht so war?



  • Der Standard garantiert dir, dass das was du tun willst, undefiniertes Verhalten ist.



  • otze schrieb:

    Der Standard garantiert dir, dass das was du tun willst, undefiniertes Verhalten ist.

    So etwas habe ich irgendwie geahnt. 😞



  • es ist so:
    wenn du eine union hast und da etwas reinschreibst in ein element, dann ist es legal, auf genau dieses element lesend zuzugreifen. greifst du aber auf ein anderes zu, ist es undefiniert durchd en std

    in deinem beispiel wird es wahrscheinlich bei den meisten compilern gutgehen, aber garantiert is nix


  • Mod

    cooky451 schrieb:

    Hi,

    union V
    {
      float data[4];
      struct 
      {
        float x, y, z, w;
      };
    };
    

    Wird hier garantiert, dass die Daten genau übereinanderliegen, also dass x == data[0], ...?
    Falls nicht, habt ihr schon mal irgendeinen Compiler gesehen, bei dem das nicht so war?

    Zunächst einmal wird dieser Code ill-formed.

    struct 
      {
        float x, y, z, w;
      };
    

    Der Standard kennt keine anonymen structs.

    union V
    {
      float data[4];
      struct data_t
      {
        float x, y, z, w;
      } data_;
    };
    V foo;
    

    Der Standard gerantiert hier, dass

    &foo.data[0] == &foo.data_.x
    

    gilt. Es ist streitig, ob äquivalente Relationen für die folgenden Member auch gelten muss (d.h. ob die Aufzählung der Gründe für Padding in einer Klasse, so wie sie im Standard steht, abschließend ist). Jedenfalls ist es möglich, das Programm so zu formluieren, dass es garantiert ill-formed wird, falls ein Compiler solches zusätzliches Padding benutzt.

    union V
    {
      float data[4];
      struct data_t
      {
        float x, y, z, w;
      } data_;
      static_assert(offsetof(data_t, w) == 3*sizeof(float), "unexpected padding in data_t")
    };
    V foo;
    


  • Skym0sh0 schrieb:

    greifst du aber auf ein anderes zu, ist es undefiniert durchd en std

    Eine Ausnahme ist, wenn die union zwei oder mehr POD-structs beinhaltet und diese eine gemeinsame (d.h. gleiche) Eingans-Sequenz haben. Dann ist es erlaubt, in eines der structs zu schreiben und im anderen diese Eingangs-Sequenz zu lesen:

    struct A {int iA; float fA; short sA; };
    struct B {int iB; char[sizeof(float)] cB; short sB; };
    union U {A a; B b;};
    
    int main()
    {
      A a = {12, 3, 4.5f};
      U u;
      u.a = a;
      int i = u.b.iB; //OK, trotz Zugriff auf B!
      short s = u.b.sB; //ERROR
    }
    

    Das zieht im aktuellen Fall aber nicht, weil ein struct mit einem array unioniert (?) werden soll. Aus den ganzen Absätzen zur object representation und zur layout compatibility könnte man evtl. noch lesen, dass das jeweils erste float an der gleichen Stelle im Speicher liegen müssen, und dass es ja ein POD-union ist und man deshalb da vielleicht in irgendeiner Grauzone, noch nicht ganz im UB sitzt. Für die anderen floats kanns aber ziemlich daneben gehen, weil nirgendwo steht, dass der Compiler in das struct kein Padding einbauen darf.



  • @camper, pumuckl
    Danke, hat mir sehr geholfen. Werde also versuchen es zu umgehen und sonst static_assert nehmen.

    (Ich habe diese Methode mittlerweile nur so oft gesehen, dass ich die Hoffnung hatte, dass es vielleicht doch garantiert wird.)


Anmelden zum Antworten