一个对象可以有多个有效类型吗?

Can an object have more than one effective type?

在 ABI 未将填充插入联合的平台上考虑以下代码:

union { int xi; } x;
x.xi = 1;

我认为第二行表现出未定义的行为,因为它违反了严格的别名规则:

  1. x.xi引用的对象与x引用的对象是同一个对象。两者是相同的存储区域,术语 object 在 ISO 9899:2011 §3.15 中定义为:

    object

    1 region of data storage in the execution environment, the contents of which can represent values

    2 NOTE When referenced, an object may be interpreted as having a particular type; see 6.3.2.1.

    因为一个对象只不过是一个存储区域,所以我断定xx.xi占用相同的存储空间,所以它们是同一个对象。

  2. x 有效类型 union { int xi; } 因为这是它声明的类型。见§6.5¶6:

    6  The effective type of an object for an access to its stored value is the declared type of the object, if any.87) If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.


    87) Allocated objects have no declared type.

    从¶6的写法也可以看出,每个对象只能有一个有效类型。

  3. 在语句 x.xi 中,我通过键入 int 的左值 x.xi 访问 x。这不是 §6.5 中列出的类型之一¶7:

    7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)

    • a type compatible with the effective type of the object,
    • a qualified version of a type compatible with the effective type of the object,
    • a type that is the signed or unsigned type corresponding to the effective type of the object,
    • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
    • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
    • a character type.

    88) The intent of this list is to specify those circumstances in which an object may or may not be aliased.

  4. 因此,第二行表现出未定义的行为。

这个解释显然是错误的,我对标准的误读在哪里?

错误认为xx.xi是同一个对象。

联合是一个对象,它包含成员对象1。它们是不同的对象,每个对象都有自己的类型。


1.(引自:ISO/IEC 9899:20x1 6.2.5 类型 20)
联合类型描述一组重叠的非空成员对象,每个 它有一个可选的指定名称和可能不同的类型。

除了禁止使用指针访问其他类型事物的规则外,术语 "object" 指的是连续的存储分配。自动或静态持续时间的每个单独变量都是一个独立的对象(因为一个实现可以任意地将它们分散在整个内存中)但是 malloc 创建的任何内存区域都将是一个单独的对象——有效类型 "char[]",无论如何索引和访问其中内容的许多不同方式。

如果除了针对字符指针类型的特殊规则之外,对于适当对齐的字符数组类型对象或具有没有有效的声明类型 "char[]"。以这种方式解释规则会将它们的应用限制在已声明类型的对象上。这将允许大多数在 1989 年实用的优化,但是随着编译器变得更加复杂,能够对分配的存储应用类似的优化变得更加可取;由于没有为此制定规则,因此不清楚什么是允许的或不允许的。

到 1999 年,基于指针的类型之间存在大量重叠 访问一些需要做的程序,以及基于指针的访问的种类 编译器假设程序不会这样做,所以任何一个 C99 标准 要么要求降低某些 C99 实现的效率 比以前更好,否则允许 C99 编译器任意使用 大量代码依赖于一些编译器没有的技术 支持。

C99 的作者,而不是通过定义来解决问题 指定不同别名模式的指令,试图 "clarify" 它 通过添加需要应用不同定义的语言 "object" 来自别处使用的那个,否则要求每个分配 region 保存单一类型的数组或单一结构 可能包含灵活的数组成员。后一个限制可能是可用的 在一种从头开始设计的语言中,但会有效地使 大量的C代码。然而,幸运或不幸的是,该标准的作者将摆脱这种草率的起草,因为编译器编写者,至少直到最近,更感兴趣的是做使编译器 有用[=25= 所必需的事情] 而不是为了遵守写得不好的标准而做的最低限度。

如果想要编写可与高质量编译器一起使用的代码,请确保以编译器必须迟钝而无法忽略的方式完成任何别名(例如,如果函数接收类型为 [=10 的参数) =],将其转换为 U*,然后 作为 U* 访问对象,一个不迟钝的编译器应该没有 无法识别该函数可能真的正在访问 T*)。如果一个人想编写可以与可以想象的最迟钝的编译器一起工作的代码……那是不可能的,因为标准不要求实现不能处理除了可能设计的和无用的程序之外的任何东西。如果有人想编写适用于 gcc 的代码,那么作者支持构造的意愿将比标准对它们的描述更重要。