为给定范围创建一次复合文字

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

我对 N2346::6.5.2.5/15 很困惑和 N2346::6.5.2.5/16哪个国家(emp。我的)

15 EXAMPLE 8 Each compound literal creates only a single object in a given scope

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;
}

The function f() always returns the value 1.

16 Note that if an iteration statement were used instead of an explicit goto and a labeled statement, the lifetime of the unnamed object would be the body of the loop only, and on entry next time around p would have an indeterminate value, which would result in undefined behavior.


在我看来,这句话与标准的另一部分相矛盾。恰恰:N2346::6.5.2.5/5

If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.


这意味着使用复合文字创建的块范围对象具有自动存储持续时间。N2346::6.8/3 (我的):

The initializers of objects that have automatic storage duration, and the variable length array declarators of ordinary identifiers with block scope, are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear.


所以即使goto N2346::6.5.2.5/15 示例中的语句替换为迭代语句,每次到达时都应重新创建由复合文字创建的对象。
问题 : 为什么要更换goto用迭代语句产生 UB?我的推理有什么问题?

最佳答案

even if the goto statement in the example of N2346::6.5.2.5/15 is replaced with an iteration statement the object created by compound literal should be re-created each time it's reached.


你是对的 - 但重要的一点是块的结束标志着对象存储持续时间的结束。未定义的行为在 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 内部创建的对象循环仅有效 在循环范围内 .

关于为给定范围创建一次复合文字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69070100/

相关文章:

c++ - 在常量表达式上下文中定义之前的嵌套 `constexpr` 函数调用

c - 这种对 union 行为的解释是正确的吗?

c - 从函数返回字符串会产生垃圾

c++ - 脚本引擎 - 调用 "unknown"函数

c++ - 是否允许调用参数中的typename T?

c - 为什么在 C 中允许未定义的行为

c++ - 为什么类的析构函数被调用了两次?共享指针

c - 等于表达式如何在 printf 占位符中工作?

c - 部分提交黑客排名

c - Pipe() fork() 和 exec