12

任何架构上的任何编译器都可能导致以下断言失败吗?

union { int x; int y; } u;
u.x = 19;
assert(u.x == u.y);
4

3 回答 3

6

C99 为联合的两个成员是共享初始字段序列的结构的情况做出特殊保证:

struct X {int a; /* other fields may follow */ };
struct Y {int a; /* other fields may follow */ };
union {X x; Y y;} u;
u.x.a = 19;
assert(u.x.a == u.y.a); // Guaranteed never to fail by 6.5.2.3-5.

6.5.2.3-5:为了简化联合的使用,做了一个特殊的保证:如果联合包含多个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构之一,则它允许在任何可见联合的完整类型声明的任何地方检查它们中任何一个的公共初始部分。如果对应的成员对于一个或多个初始成员的序列具有兼容的类型(并且对于位域,具有相同的宽度),则两个结构共享一个共同的初始序列。

但是,我无法为联合中的非结构化类型找到类似的保证。不过,这很可能是一个遗漏:如果该标准花了一些时间来描述甚至不一样的结构化类型必须发生的事情,那么它应该为更简单的非结构化类型阐明相同的点。

于 2013-11-07T14:51:38.737 回答
4

assert标准 C 的实现中,问题永远不会失败,因为u.y在分配 to 之后访问u.x需要将字节重新解释u.xu.y. 由于类型相同,因此重新解释会产生相同的值。

此要求在 C 2011 (N1570) 6.5.2.3 note 95 中注明,表明它源自第 6.2.6 条,其中涵盖了类型的表示。注释 95 说:

如果用于读取联合对象内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的适当部分重新解释为新类型中的对象表示在 6.2.6 中描述(有时称为“类型双关语”的过程)。这可能是一个陷阱表示。

(N1570 是一个非官方的草案,但在网上很容易获得。)

于 2013-11-08T05:12:11.597 回答
3

我相信这个问题很难以您期望的方式回答。

据我所知,读取union不是最近写入的字段的字段是未定义的行为。

因此,不可能用“否”来回答,因为任何编译器编写者都可以自由地专门检测到这一点,如果他们愿意的话,他们会出于恶意而让它失败。

于 2013-11-07T14:44:35.757 回答