gpt4 book ai didi

c++ - union 'punning' 结构 w/ "common initial sequence": Why does C (99+), 但不是 C++,规定 'visible declaration of the union type' ?

转载 作者:行者123 更新时间:2023-12-01 23:43:02 28 4
gpt4 key购买 nike

背景

通过 union 讨论类型双关的大多数未定义或实现定义的性质通常引用以下位,这里通过@ecatmur ( https://stackoverflow.com/a/31557852/2757035 ),关于标准布局的豁免 struct s 具有成员类型的“共同初始序列”:

C11 (6.5.2.3 Structure and union members; Semantics):

[...] if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.



C++03 ( [class.mem]/16 ):

If a POD-union contains two or more POD-structs that share a common initial sequence, and if the POD-union object currently contains one of these POD-structs, it is permitted to inspect the common initial part of any of them. Two POD-structs share a common initial sequence if corresponding members have layout-compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.



这两个标准的其他版本有相似的语言;从 C++11 开始
使用的术语是标准布局而不是 POD。

由于不需要重新解释,这并不是真正的类型双关语,只是应用于 union 的名称替换。成员(member)访问。 C++17 的提案(臭名昭著的 P0137R1)使用类似“访问就像另一个结构成员被提名”这样的语言来明确说明这一点。

但请注意粗体 - “ 任何可以看到完整类型 union 声明的地方 ” - C11 中存在的子句,但在 2003、2011 或 2014 年的 C++ 草案中没有任何地方(几乎完全相同) ,但后来的版本用新术语标准布局替换了“POD”)。无论如何,“可见声明 union”在任何 C++ 标准的相应部分中都完全没有 type bit。

@loop 和 @Mints97,在这里 - https://stackoverflow.com/a/28528989/2757035 - 显示这条线也是 在 C89 中不存在,首次出现在 C99 并从那时起一直使用 C(不过,再一次,永远不会过滤到 C++)。

围绕这个的标准讨论

[剪断 - 见我的答案]

问题

因此,我的问题是:
  • 这是什么意思? 什么被归类为“可见声明”?该条款是否旨在缩小 - 或扩大 - 这种“双关语”定义行为的上下文范围?
  • 我们是否认为 C++ 中的这种省略是非常刻意的?
  • C++ 与 C 不同的原因是什么? C++ 是否只是从 C89 中“继承”了这一点,然后决定——或者更糟的是,忘记——与 C99 一起更新?
  • 如果差异是故意的,那么 C 与 C++ 中的 2 种不同处理方式有什么优点或缺点?
  • 它在编译或运行时有什么有趣的后果(如果有的话)? 例如,@ecatmur 在回复我在他的原始答案(如上链接)中指出这一点的评论中,推测如下。

  • I'd imagine it permits more aggressive optimization; C can assume that function arguments S* s and T* t do not alias even if they share a common initial sequence as long as no union { S; T; } is in view, while C++ can make that assumption only at link time. Might be worth asking a separate question about that difference.



    好吧,我在这里,问!我对有关此问题的任何想法都非常感兴趣,尤其是:(任一)标准的其他相关部分、委员会成员或其他受人尊敬的评论员的引述、可能已经注意到实际差异的开发人员的见解 - 假设任何编译器甚至费心强制执行 C 的附加条款 - 等等。目的是生成有关此 C 条款及其(有意或无意)从 C++ 遗漏的相关事实的有用目录。所以,我们走吧!

    最佳答案

    我已经通过迷宫找到了一些关于此的重要资源,并且我认为我已经对其进行了非常全面的总结。我将此作为答案发布,因为它似乎解释了 C 子句的(IMO 非常误导)意图以及 C++ 没有继承它的事实。如果我发现进一步的支持 Material 或情况发生变化,这将随着时间的推移而发展。

    这是我第一次尝试总结一个非常复杂的情况,即使对于许多语言架构师来说,这似乎也没有明确定义,所以我欢迎关于如何改进这个答案的澄清/建议 - 或者如果有人有一个更好的答案。

    最后,一些具体的评论

    通过模糊相关的线程,我找到了@tab 的以下答案 - 非常感谢其中包含的(如果不是结论性的)GCC 和工作组缺陷报告的链接:answer by tab on StackOverflow

    GCC 链接包含一些有趣的讨论,并揭示了部分委员会和编译器供应商的大量混淆和相互矛盾的解释 - 围绕 union 的主题。成员(member)struct C 和 C++ 中的 s、双关语和别名。

    最后,我们与主要事件相关联 - 另一个 BugZilla 线程,Bug 65892 ,包含 有用的讨论。特别是,我们找到了两个关键文档中的第一个的方法:

    C99 中添加行的原点

    C proposal N685是关于 union 的可见性的附加条款的起源类型声明。通过某些声称(参见 GCC 线程 #2)是对“公共(public)初始序列”许可的完全误解,N685 确实是 旨在允许放宽“公共(public)初始序列”的混叠规则struct在 TU 内知道一些 union包含上述 struct 的实例类型 ,正如我们从这句话中看到的:

    The proposed solution is to require that a union declaration be visible if aliases through a common initial sequence (like the above) are possible. Therefore the following TU provides this kind of aliasing if desired:


    union utag {
    struct tag1 { int m1; double d2; } st1;
    struct tag2 { int m1; char c2; } st2;
    };

    int similar_func(struct tag1 *pst2, struct tag2 *pst3) {
    pst2->m1 = 2;
    pst3->m1 = 0; /* might be an alias for pst2->m1 */
    return pst2->m1;
    }

    从 GCC 的讨论和下面的评论(例如@ecatmur 的)来看,这个提案 - 似乎强制要求允许对任何 struct 使用别名。类型在某些 union 中具有某些实例此 TU 可见 - 似乎受到了很大的 mock ,很少实现 .

    很明显,在不完全削弱许多优化的情况下满足对附加条款的这种解释是多么困难 - 几乎没有好处,因为很少有编码人员想要这种保证,而那些这样做的人只需打开 fno-strict-aliasing (IMO 表明存在更大的问题)。如果实现,此津贴更有可能将人们抓获并与 union 的其他声明进行虚假互动。 s,比有用。

    省略 C++ 中的行

    继此以及我在其他地方发表的评论之后, @Potatoswatter in this answer here on SO指出:

    The visibility part was purposely omitted from C++ because it's widely considered to be ludicrous and unimplementable.



    换句话说, 看起来 C++ 故意避免采用这个附加条款,可能是因为它被广泛认为是荒谬的。 在要求对此进行“记录在案”引用时,Potatoswatter 提供了有关该线程参与者的以下关键信息:

    The folks in that discussion are essentially "on the record" there. Andrew Pinski is a hardcore GCC backend guy. Martin Sebor is an active C committee member. Jonathan Wakely is an active C++ committee member and language/library implementer. That page is more authoritative, clear, and complete than anything I could write.



    Potatoswatter 在上面链接的同一个 SO 线程中得出结论,C++ 故意排除了这一行,没有对指向公共(public)初始序列的指针进行特殊处理(或者,充其量是实现定义的处理)。与任何其他指标相比, future 是否会明确定义他们的治疗方法,还有待观察;与我下面关于 C 的最后一部分进行比较。但目前,它不是(再次,IMO,这很好)。

    这对 C++ 和实际的 C 实现意味着什么?

    因此,对于来自 N685 的恶意行......“抛弃”......我们又回到假设指向公共(public)初始序列的指针在别名方面并不特殊。仍然。值得确认一下 C++ 中的这一段在没有它的情况下意味着什么。好吧,上面的第二个 GCC 线程链接到另一个 gem:

    C++ defect 1719 .此提案已达 DRWP 状态:“一个 DR 问题,其解决方案反射(reflect)在当前工作文件中。工作文件是标准 future 版本的草案”- cite .这是在 C++14 之后或至少在我这里的最终草案(N3797)之后 - 并提出了 重要的,在我看来很有启发性,重写这一段的措辞 , 如下。我将我认为的重要更改加粗,{这些评论}是我的:

    In a standard-layout union with an active member {"active" indicates a union instance, not just type} (9.5 [class.union]) of struct type T1, it is permitted to read {formerly "inspect"} a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2. [Note: Reading a volatile object through a non-volatile glvalue has undefined behavior (7.1.6.1 [dcl.type.cv]). —end note]



    这似乎澄清了旧措辞的含义:对我来说,它表示任何特别允许的 union之间的“双关语”成员(member)struct具有共同初始序列的 s 必须通过父级 union 的实例来完成。 - 而不是基于 structs 的类型(例如,指向它们的指针传递给某个函数)。这种措辞似乎排除了任何其他解释,如 N685。我会说,C 最好采用这种方法。嘿嘿,说起来,往下看!

    结果是——正如@ecatmur 和海湾合作委员会门票中很好地证明的那样——这留下了 union成员(member)struct s 根据 C++ 中的定义,实际上在 C 中,与任何其他 2 个正式无关的指针遵循相同的严格别名规则。 能够读取非事件的公共(public)初始序列的明确保证 union成员(member) struct s 现在的定义更加明确,不包括 N685 为 C 尝试的模糊且难以想象的单调乏味的强制“可见性”。根据这个定义,主要编译器的行为与 C++ 的预期一致。至于C?

    这条线在 C 中的可能反转/在 C++ 中的澄清

    同样值得注意的是,C 委员会成员 Martin Sebor 也希望用这种精美的语言来解决这个问题:

    Martin Sebor 2015-04-27 14:57:16 UTC If one of you can explain the problem with it I'm willing to write up a paper and submit it to WG14 and request to have the standard changed.

    Martin Sebor 2015-05-13 16:02:41 UTC I had a chance to discuss this issue with Clark Nelson last week. Clark has worked on improving the aliasing parts of the C specification in the past, for example in N1520 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1520.htm). He agreed that like the issues pointed out in N1520, this is also an outstanding problem that would be worth for WG14 to revisit and fix."



    Potatoswatter 鼓舞人心地总结道:

    The C and C++ committees (via Martin and Clark) will try to find a consensus and hammer out wording so the standard can finally say what it means.



    我们只能希望!

    再次,欢迎所有进一步的想法。

    关于c++ - union 'punning' 结构 w/ "common initial sequence": Why does C (99+), 但不是 C++,规定 'visible declaration of the union type' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34616086/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com