"block is entered recursively" 是什么意思?

What's the meaning of "block is entered recursively"?

我在 reddit 上问了一个问题。这个问题实际上是 Why does the starting point of a lifetime of an automatic object(which doesn't have VLA) precede a scope of an object?
我得到了可以作为我的问题示例的答案。

代码

#include <stdio.h>

int main(void) {
    int i = 0;
back:
    printf("i = %d", i);
    int j;
    if (i < 5) {
        if (i == 0)
            j = 0;
        j += i;
        printf(", j = %d\n", j);
        i++;
        goto back;
    }
    printf("\n");
}

输出

i = 0, j = 0
i = 1, j = 1
i = 2, j = 3
i = 3, j = 6
i = 4, j = 10
i = 5

但是有人说“j 的值在达到其声明时变得不确定,...”因为 C17 6.2.4p6(加粗)

For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

仅转到当前块中的标签不同于在递归函数或迭代语句中重复整个关联块。从这个角度来看,我不认为j不受规则影响(但这只是我的想法)。

顺便说一句,我认为无论我们以何种方式思考,都会存在矛盾。
-如果int j;没有在每个序列中重新创建,它就是一个重新定义。
- 如果在每个序列中重新创建 int j;,则 j 应具有来自第二个序列的垃圾值。但是输出显示为好像保留了 'j' 的值。

我一遍又一遍地阅读引用的部分文档,但无法理解。我错过了什么?

重要的部分在后面:

If an initialization is specified for the object, [...]; otherwise, the value becomes indeterminate each time the declaration is reached.

每次达到int jj的值就变得不确定。 j 保留以前的值也是垃圾值的一个例子,因为它可以是 any 值。如果您的代码依赖于该值,则意味着您的代码的行为未定义。

If the block is entered recursively, a new instance of the object is created each time

“块”通常以 { 开头并以 } 结尾。该段是递归函数。

void func()
{ // block start
    int a; // new instance of object created each time, even recursively
    func(); // enter the block recursively
} // block end

您的代码中有一个块是使用 int main(void) { 创建的,您的代码中的另一个块是 if (i < 5) { 之后的块。 那个if (i < 5) {不是递归进入的,是进入,然后离开,再进入,再离开。

If int j; isn't created anew in each sequence, it is a redefinition.

引用那句话:

For such an object [object with automatic storage duration, see previous point in standard] that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.

j 标识的对象的生命周期从进入块开始,所以我认为它不是“重新创建的”。

int main(void) { // lifetime of "object j" starts here
                 // but you can't access it, no identifier is associated with it
back:;
    int j; // the identifier `j` is associated with "object j"
           // the value of the object associated with `j` is indeterminate
           // _each time_ execution flow gets here
    goto back;
} // lifetime of "object j" ends here (or at `return`)
  // scope of identifier `j` also ends here