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

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

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

我相信第二行显示未定义的行为,因为它违反了严格的别名规则:

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

    宾语

    执行环境中的1个数据存储区域,其内容可以表示值

    2注意引用时,对象可能被解释为具有特定类型; 见6.3.2.1。

    由于对象不仅仅是一个存储区域,我得出结论,由于xx.xi占用相同的存储空间,因此它们是同一个对象。

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

    6访问其存储值的对象的有效类型是对象的声明类型(如果有)。 87)如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及后续访问的有效类型修改存储的值。 如果使用memcpymemmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。


    87)分配的对象没有声明的类型。

    根据¶6的措辞,显然每个对象只能有一种有效类型。

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

    7对象的存储值只能由具有以下类型之一的左值表达式访问: 88)

    • 与对象的有效类型兼容的类型,
    • 与对象的有效类型兼容的类型的限定版本,
    • 与对象的有效类型对应的有符号或无符号类型的类型,
    • 与有效类型的对象的限定版本对应的有符号或无符号类型的类型,
    • 在其成员中包含上述类型之一的聚合或联合类型(包括递归地,子聚合或包含联合的成员),或者
    • 一个字符类型。

    88)此列表的目的是指定对象可能或可能没有别名的情况。

  4. 因此,第二行表现出不确定的行为。

由于这种解释显然是错误的,我在哪里误读标准?

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

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


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

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

如果除了字符指针类型的特殊规则之外,对于字符数组类型的适当对齐的对象,或者对于没有声明类型的对象,存在相应的规则,则可以使关于指针类型访问的C89规则可行。有效地“char []”。 以这种方式解释规则会将其应用程序限制为已声明类型的对象。 这将允许大多数在1989年实际应用的优化,但随着编译器变得越来越复杂,能够对分配的存储应用类似的优化变得更加可取; 由于没有为此制定规则,因此对于允许或不允许的内容几乎没有明确规定。

到1999年,某些程序需要执行的基于指针的访问类型与编译器假定程序不会执行的基于指针的访问类型之间存在大量重叠,因此任何单个C99标准都要么需要一些C99实现的效率低于以往,或者允许C99编译器使用大量代码依赖于某些编译器不支持的技术而任意行为。

C99的作者,而不是通过定义指令来指定不同的别名模式来解决这种情况,试图通过添加要求从其他地方使用的“对象”应用不同定义的语言来“澄清”它,或者要求每个分配区域包含单个类型的一个数组或可包含灵活数组成员的单个结构。 后一种限制可能适用于从头开始设计的语言,但实际上会使大量C代码无效。 然而,幸运或不幸的是,标准的作者要摒弃这种草率的起草,因为编译器编写者至少直到最近才更有兴趣做一些必要的事情来使编译器变得有用,而不是做出符合的最低要求。标准不好的标准。

如果想要编写可与高质量编译器一起使用的代码,请确保以编译器必须忽略忽略的方式完成任何别名(例如,如果函数接收类型为T*的参数,则将其强制转换为U* ,然后作为U*访问对象,一个不是钝的编译器应该没有识别该函数可能真正访问T*麻烦。 如果有人想编写可以使用最可靠的编译器编写的代码……这是不可能的,因为标准不要求实现无法处理除可能设计和无用的程序之外的任何其他内容。 如果想要编写可以在gcc上运行的代码,那么作者支持构造的意愿将远远超过标准对它们所说的内容。