Union of layout-compatible types

前端 未结 1 1713
走了就别回头了
走了就别回头了 2021-02-19 13:05

Look at this code:

struct A {
    short s;
    int i;
};
struct B {
    short s;
    int i;
};

union U {
    A a;
    B b;
};

int fn() {
    U u;
    u.a.i = 1         


        
1条回答
  •  不知归路
    2021-02-19 13:29

    Yes, this is defined behavior. First lets see what the standard has to say about A and B. [class.prop]/3 has

    A class S is a standard-layout class if it:

    • has no non-static data members of type non-standard-layout class (or array of such types) or reference,
    • has no virtual functions and no virtual base classes,
    • has the same access control for all non-static data members,
    • has no non-standard-layout base classes,
    • has at most one base class subobject of any given type,
    • has all non-static data members and bit-fields in the class and its base classes first declared in the same class, and
    • [...] (nothing said here has any bearing in this case)

    So A and B are both standard layout types. If we look at [class.mem]/23

    Two standard-layout struct types are layout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes ([basic.types]).

    and [class.mem]/22

    The common initial sequence of two standard-layout struct types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types, either both entities are declared with the no_­unique_­address attribute ([dcl.attr.nouniqueaddr]) or neither is, and either both entities are bit-fields with the same width or neither is a bit-field.

    and [class.mem]/25

    In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated. [ Example:

    struct T1 { int a, b; };
    struct T2 { int c; double d; };
    union U { T1 t1; T2 t2; };
    int f() {
      U u = { { 1, 2 } };   // active member is t1
      return u.t2.c;        // OK, as if u.t1.a were nominated
    }
    

    — end example ] [ Note: Reading a volatile object through a glvalue of non-volatile type has undefined behavior ([dcl.type.cv]). — end note ]

    Then we have that the classes have the same common initial sequence, are laid out the same, and accessing the same member of the non-active type is treated as if accessing that member of the active type.

    0 讨论(0)
提交回复
热议问题