布局兼容类型的目的是什么?

9

标准定义了两种类型何时是布局兼容的。但是,我没有在标准中看到两种类型是布局兼容时的后果。似乎布局兼容是一个没有被使用的定义。

布局兼容的目的是什么?

注:据说这可能意味着类型具有相同的布局(每个对应成员的offsetof相同),因此例如对于可平凡复制的类型,可以在它们之间复制基础字节。但是我没有在标准中看到类似的内容。


通用初始序列保证计数,是否算作使用此定义?尽管是传递性的… - StoryTeller - Unslander Monica
@bolov:你说得对,这个定义确实用于指向布局兼容类型的指针(也许这就是答案……)。但我期望布局兼容类型有更强的属性。 - geza
@geza:一个有趣的检查布局兼容性的提案。这是由于代码依赖于布局兼容性而发起的。http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0466r2.pdf - P.W
@P.W: 我想知道那段代码是什么意思:“一个依赖于两种类型兼容布局的代码片段”。 - geza
@geza:我也很好奇。这一定涉及到reinterpret_cast。如果我确定了,我就会发布一个答案。 :) - P.W
显示剩余5条评论
2个回答

9

标准确实定义了一个特定情况,其中布局兼容性很重要:在union中。如果两个成员具有布局兼容性,并且其中一个是活动的union成员,则可以通过对任何布局兼容成员的指针/引用访问该对象。这是“通用初始序列”规则的结果。


谢谢提供信息!为了进一步参考,这里是规则,它说明了你所描述的内容。 - geza
此外,由于这个规则的存在,难道不是这样吗,也就是说,我所描述的(offsetof 对应成员相同,布局必须相同)即使没有明确说明,也必须是正确的吗?我的意思是,如果布局不同,那么联合规则就无法满足。 - geza
有趣的是,具有相同基础类型的枚举是布局兼容的,如果结构体成员是2个布局兼容的枚举,则可以检查常见的初始序列,但由于违反了严格别名规则,您将会遇到未定义行为。 - Language Lawyer

2
标准并不试图强制要求所有实现都适用于所有目的。因此,旨在适用于标准所要求支持以外目的的优质实现通常需要扩展语言的语义。它们可以通过简单而有用的方式之一来实现这一点,即在某些情况下,如果标准的某些部分定义或暗示了某些操作的行为,但另一部分说重叠范畴的操作会导致 UB,则将处理行为作为前面部分定义或暗示的行为。例如,在许多编译器上,存在一个选项(通常使用-fno-strict-aliasing标志启用),该选项表示任何行为在没有类型访问规则的情况下定义的程序将以那种方式处理,即使这些规则会说该程序调用UB也是如此。
尽管有很少的情况,其中两个结构具有布局兼容性会导致行为被标准定义,否则就不会,但有很多情况下,它会暗示实现在缺少这些类型访问规则的情况下必须如何行事(因为这基本上使得实现无法做其他事情)。例如,如果结构类型T1和T2具有布局兼容性,则这意味着,如果将指向T1的指针转换为T2*,则使用后者指针对结构的任何成员进行的任何操作都将访问T1对象的相应成员。
因为并非所有程序都需要这些能力,所以标准不要求所有实现都提供它们。另一方面,适用于低级编程的实现将提供手段,通过这些手段,可以交替使用处理一种类型的代码部分来处理布局兼容类型,无论标准是否要求(不提供此功能的实现仅适用于低级编程以外的用途)。
我认为,正式承认适用于低级编程和不适用于低级编程的实现类别,而不是试图为所有实现定义单一行为集合,将极大地改善标准。尽管如此,像“布局兼容性”这样的概念大大提高了可在适用于低级编程的实现之间移植的构造范围。

1
简而言之,当编译器遇到未定义的行为时,它完全可以合法地定义该行为。;P - Justin Time - Reinstate Monica
@JustinTime:如果一个实现定义了某些操作的行为,但标准将一组重叠的操作分类为违反运行时约束(从而调用未定义行为),则不清楚前面的定义是否应该适用于违反约束的情况。因此,我回答中第二个句子的意义就在于此。 - supercat
1
我知道,我只是在用点儿幽默的口吻总结一下,指出当编译器遇到未定义的行为时,提供自己的定义(代替官方的“未定义”)作为编译器扩展的响应是有效的。 - Justin Time - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接