【问题标题】:Semantic difference between function return and assignment函数返回和赋值之间的语义差异
【发布时间】:2021-11-22 20:34:37
【问题描述】:

标准在 6.8.6.4 中提供了一个示例:

示例:

struct s { double i; } f(void);
union {
    struct {
        int f1;
        struct s f2;
    } u1;
    struct {
        struct s f3;
        int f4;
    } u2;
} g;
struct s f(void)
{
    return g.u1.f2;
}
/* ... */
g.u2.f3 = f();

没有未定义的行为,尽管如果 分配是直接完成的(不使用函数调用来获取 值)。

您能否解释一下为什么在直接分配的情况下会有 UB。这似乎与标准中示例上面的定义相矛盾:

如果表达式的类型与返回类型不同 它出现的函数,值被转换为 赋值给具有函数返回类型的对象。

所以return 的语义和赋值应该是一样的。

【问题讨论】:

  • 您是否看到脚注 #175 中提到了关于重叠的差异(6.5.16.1 §3)? “return 语句不是赋值。”我没有搜索标准,但是没有地方定义函数返回值是临时对象吗?
  • @thebusybee:临时对象仅用于返回包含数组的结构。 (因为在引用数组时需要一个对象,因为它必须转换为指针,如f().array[3]。)
  • @EricPostpischil 所以一个积极优化的编译器可能会内联函数并编译一个赋值?嗯,听起来像是一个有趣的实验,并将其与显式赋值的汇编进行比较。
  • @thebusybee 当然我看到了,但脚注不规范......
  • 但他们解释文字。 ;-) 在这种情况下,它会导致您想要的答案。

标签: c return language-lawyer


【解决方案1】:

这里的重点不是转换。示例中,return语句中的值与函数返回类型相同,无需转换。

关键点是要求(标准条款 6.5.16.1,第 3 段)只有在重叠准确的情况下才为重叠对象定义分配:

如果存储在一个对象中的值是从另一个以任何方式重叠的对象中读取的 存储第一个对象,则重叠应准确,两个对象应 具有兼容类型的合格或不合格版本;否则,行为是 未定义。

因此分配:

g.u2.f3 = g.u1.f2;

将是未定义的行为(因为对象是“非完全重叠”),但在示例中,分配是通过函数调用发生的,因此分配不是直接在非完全重叠的对象之间进行,因此不是未定义的行为。

【讨论】:

  • 很好,谢谢。
猜你喜欢
  • 2017-11-14
  • 1970-01-01
  • 2022-01-03
  • 2016-05-14
  • 2013-07-15
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 2020-09-08
相关资源
最近更新 更多