【发布时间】:2021-09-06 06:38:14
【问题描述】:
我对@987654321@ 和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