14

看看这段代码:

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;
    return u.b.i;
}

是否保证fn()退货1

注意:这是对此的后续问题。

4

1 回答 1

12

是的,这是定义的行为。首先让我们看看标准对Aand有什么看法B[class.prop]/3

如果满足以下条件,则 S 类是标准布局类:

  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  • 没有虚函数,也没有虚基类,
  • 对所有非静态数据成员具有相同的访问控制,
  • 没有非标准布局的基类,
  • 最多有一个任何给定类型的基类子对象,
  • 具有该类及其基类中的所有非静态数据成员和位字段,并首先在同一类中声明,并且
  • [...](这里所说的在这种情况下没有任何影响)

所以AB都是标准布局类型。如果我们看一下[class.mem]/23

如果两个标准布局结构类型的公共初始序列包含两个类的所有成员和位字段([basic.types]),则它们是布局兼容的类。

[class.mem]/22

两种标准布局结构类型的共同初始序列是声明顺序中非静态数据成员和位字段的最长序列,从每个结构中的第一个此类实体开始,以便相应实体具有布局兼容类型,要么两个实体都用 no_unique_address 属性 ([dcl.attr.nouniqueaddr]) 声明,要么两者都不是,要么两个实体都是具有相同宽度的位域,要么都不是位域。

[class.mem]/25

在具有结构类型 T1 的活动成员的标准布局联合中,允许读取结构类型 T2 的另一个联合成员的非静态数据成员 m,前提是 m 是 T1 和 T2 的公共初始序列的一部分;行为就像T1的相应成员被提名一样。[ 例子:

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
}

—结束示例] [注意:通过非易失性类型的glvalue读取易失性对象具有未定义的行为([dcl.type.cv])。——尾注]

然后我们有这些类具有相同的公共初始序列,布局相同,并且访问非活动类型的相同成员被视为访问活动类型的该成员。

于 2018-10-29T17:54:34.820 回答