布局兼容类型的目的是啥?

Posted

技术标签:

【中文标题】布局兼容类型的目的是啥?【英文标题】:What's the purpose of layout-compatible types?布局兼容类型的目的是什么? 【发布时间】:2019-04-02 03:45:21 【问题描述】:

标准defines 当两种类型布局兼容。但是,我在标准中的任何地方都看不到当两种类型布局兼容时会产生什么后果。似乎 layout-compatible 是一个没有在任何地方使用的定义。

layout-compatible的目的是什么?

注意:假设这可能意味着类型具有相同的布局(offsetof 对于每个相应的成员都是相同的),因此例如,对于普通可复制类型,可以在它们之间复制底层字节。但是我在标准中没有看到这样的东西。

【问题讨论】:

通用初始序列保证不算作使用这个定义吗?虽然是传递性的...... 我唯一能找到的是 §12.2.21 定义通用初始序列和 §6.7.2.3 “指向布局兼容类型的指针应具有相同的值表示和对齐要求”(n4713)跨度> @StoryTeller:如果他们有共同的初始序列,那么后果是什么?这些类型有什么属性可以利用吗? ***.com/questions/21956354/… 来自那里的答案(高级代表用户)“AFAICT 标准实际上并没有说明布局兼容类型可以做什么和不能做什么。”也许......一个骗子...... @bolov:你说得对,该定义确实用于指向布局兼容类型的指针(也许这就是答案......)。但我期待布局兼容类型的一些更强大的属性。 【参考方案1】:

该标准确实定义了一种布局兼容性很重要的特定情况:unions。如果两个成员是布局兼容的,其中一个是活动的union 成员,那么您可以通过指向该union 的任何布局兼容成员的指针/引用来访问该对象。这是the "common initial sequence" rule 的结果。

【讨论】:

感谢您的信息!供进一步参考,this 是说明您所描述内容的规则。 另外,因为这个规则,是不是这样,我所描述的(offsetof对于每个对应的成员都是一样的,布局必须相同)必须是真的,即使它没有明确表示?我的意思是,如果布局不同,则无法满足联合规则。 有趣的是,具有相同底层类型的枚举是布局兼容的,如果结构的成员是 2 个布局兼容的枚举,你可以检查公共初始序列,除非你会由于违反严格的别名规则而有 UB【参考方案2】:

该标准并未尝试强制要求所有实现都适用于所有目的。因此,旨在适用于超出标准需要支持的目的的质量实现通常需要扩展语言的语义。他们可以做到这一点的最简单和最有用的方法之一是说,在某些情况下,标准的部分定义或暗示某些动作的行为,但另一部分说重叠的动作类别调用 UB,他们会将行为处理为由前几部分定义或暗示。例如,在许多编译器上,有一个选项(通常使用-fno-strict-aliasing 标志启用)表示任何在没有类型访问规则的情况下定义其行为的程序都将以这种方式处理,即使这些规则会说程序调用了 UB。

虽然在相对较少的情况下,两个结构是布局兼容的事实会导致标准定义的行为,否则它不会,但在许多情况下,它会暗示实现必须如何在没有这些类型访问规则(通过使实现基本上不可能做任何其他事情)。例如,如果结构类型 T1 和 T2 是布局兼容的,这表明如果指向 T1 的指针转换为 T2*,则使用后者指针对结构成员的任何操作都将访问相应的成员T1 对象。

因为并非所有程序都需要这种能力,所以标准并不要求所有实现都提供这些能力。另一方面,适用于低级编程的实现将提供一种方法,通过该方法,设计用于处理一种类型的代码部分可用于可互换地处理布局兼容类型,无论标准是否要求它们(实现不仅仅局限于低级编程以外的用途)。

我认为,通过正式承认适合低级编程的实现类别和其他没有声称是的实现类别,而不是试图为所有实现定义单一的一组行为,我认为该标准将得到极大的改进。尽管如此,定义诸如“布局兼容性”之类的概念极大地改进了在适合低级编程的实现中可移植的构造范围

【讨论】:

或者简而言之,当编译器遇到未定义的行为时,仅仅简单地定义行为是完全合法的。 ;P @JustinTime:如果一个实现定义了某些动作的行为,但标准将重叠的动作类别归类为违反运行时约束(并因此调用未定义行为),则可能不清楚以前的定义应该适用于违反约束的情况。因此,我的回答中第二句话的意义。 我知道,我只是在总结它(舌头稍微有点脸颊),指出当编译器遇到未定义的行为时,提供自己的定义(代替官方的“它未定义”)作为编译器扩展是一个有效的响应。

以上是关于布局兼容类型的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章

“不兼容的类型:void 不能转换为 ...”是啥意思?

为什么不同布局兼容类型的两个数组本身也不兼容布局?

api 特定类型定义(例如 GLsizei GLint GLvoid)的目的是啥?

在 NgRx 中强类型化存储的目的是啥?

在 Typescript 上声明类型时泄漏管道的目的是啥

VHDL 中的“std_logic”枚举类型的目的是啥?