【问题标题】:Compound literal is created once for a given scope为给定范围创建一次复合文字
【发布时间】:2021-09-06 06:38:14
【问题描述】:

我对@9​​87654321@ 和N2346::6.5.2.5/16 哪个状态(雇员我的)感到很困惑

15 示例 8 每个复合字面量仅在 给定范围

struct s { int i; };
int f (void)
{
    struct s *p = 0, *q;
    int j = 0;
    again:
        q = p, p = &((struct s){ j++ });
        if (j < 2) goto again;
    return p == q && q->i == 1;
}

函数 f() 总是返回值 1。

16 请注意,如果使用迭代语句而不是 显式 goto 和标记语句,未命名的生命周期 对象将只是循环的主体,下次进入时 p 周围会有一个不确定的值,这会导致 未定义的行为

在我看来,这句话与标准的另一部分相矛盾。准确地说:

N2346::6.5.2.5/5

如果复合字面量出现在函数体之外,则 对象具有静态存储持续时间;否则,它具有自动 与封闭块关联的存储持续时间。

意味着使用复合字面量创建的块范围对象具有自动存储期限。

N2346::6.8/3(我的雇员):

具有自动存储持续时间的对象的初始化器,以及 普通标识符的可变长度数组声明符 块作用域,被评估并且值被存储在对象中s (包括在没有 initializer) 每次按顺序到达声明时 执行,就好像它是一个声明,并且在每个声明中 声明符出现的顺序。

因此,即使N2346::6.5.2.5/15 示例中的goto 语句被替换为迭代语句,复合文字创建的对象每次到达时都应重新创建。

问题:为什么用迭代语句替换goto 会产生UB?我的推理有什么问题?

【问题讨论】:

  • 简单地说——指针正在引用不再存在的对象。与退出函数时返回指向自动对象的指针相同
  • 我想知道标准的作者在编写复合文字的生命周期规则时是否考虑过涉及goto 的极端情况?不通过函数延长它们的生命周期的理由是这样做会表明循环的每次迭代都会创建一个新对象,但是将生命周期限制在块范围内并不能避免这种极端情况。事实上,将生命周期限制为块范围会不必要地损害复合文字的有用性,并且只创建一个对象的规范将禁止循环展开优化......
  • ...循环的每次迭代都有不同的对象,这对于 const 限定的文字有时可能非常有用(例如,如果内部循环将 i 从 0 迭代到 4,并使用复合文字(const S){1,2,3,i}; 编译器可能会有效地生成五个静态持续时间对象,i 的每个值对应一个,并让内部循环的每个展开迭代传递一个此类对象的地址。

标签: c language-lawyer undefined-behavior compound-literals


【解决方案1】:

即使 N2346::6.5.2.5/15 示例中的 goto 语句是 用迭代语句替换由复合创建的对象 每次到达时都应重新创建字面量。

你是对的 - 但重要的是,块的结束标志着对象存储持续时间的结束。未定义的行为在第二次迭代中的q = p 上触发,此时p 不再有效,并且还在迭代语句之外的return 行上触发。


更具体地说,该标准暗指这样的代码:

struct s { int i; };
int f (void)
{
    struct s *p = 0, *q;
    int j = 0;
    for (j = 0; j < 2; j++)
    {
        q = p; // p is invalid in the second iteration
        p = &((struct s){ j++ });
    } // end of block - p is no longer valid!

    // p points to an object whose storage duration has expired, and so this is undefined behavior
    return p == q && q->i == 1;
}

您可以看到最终的return 语句引用了一个对象,该对象的存储期限在for 块的末尾到期,并且q 变量被分配给在第二次迭代中未定义的指针。

goto 的用法与 for 循环之类的迭代语句之间的明显区别在于,在 for 循环内创建的对象仅在循环范围内有效

【讨论】:

  • 谢谢,没听懂标准的意思。
猜你喜欢
  • 1970-01-01
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 2012-09-04
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
相关资源
最近更新 更多