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

Compound literal is created once for a given scope

我对 N2346::6.5.2.5/15N2346::6.5.2.5/16 感到很困惑,这说明(emp.mine)

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.

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

问题:为什么用迭代语句替换 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 循环中创建的对象仅在 内部有效循环范围.