【发布时间】:2020-11-22 13:43:11
【问题描述】:
我在 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(用我的粗体字)
对于这样一个没有变长数组类型的对象,它的生命周期从入口开始 进入与其关联的块,直到该块的执行以任何方式结束。 (输入一个 封闭块或调用函数会挂起,但不会结束当前块的执行。)如果 递归进入块,每次都会创建一个新的对象实例。 对象的初始值是不确定的。如果为对象指定了初始化,则每次在执行块时到达声明或复合文字时都会执行它;否则,每次达到声明时,值都会变得不确定。
仅转到当前块中的标签不同于在递归函数或迭代语句中重复整个关联块。从这个角度来看,我不认为j 不受规则影响(但这只是我的想法)。
顺便说一句,我认为无论我们以哪种方式思考,都存在矛盾。
- 如果int j; 没有在每个序列中重新创建,则它是重新定义。
- 如果int j; 在每个序列中重新创建,j 将具有来自第二个序列的垃圾值。但输出显示为好像保留了“j”的值。
我一遍又一遍地阅读引用的部分文档,但无法理解。我错过了什么?
【问题讨论】:
-
goto不是递归,关于递归的部分在这里不适用。 -
比递归更重复
-
你只是好奇吗?因为像这样使用 goto for 循环从来都不是很好的理由。
-
你怎么知道它不是垃圾值?一个常见的垃圾值是“之前的任何东西”
-
重新“如果 int j;不是在每个序列中重新创建,而是重新定义”:不,声明不是像语句一样执行的代码。如果声明存在于代码中的某个点,它会告诉编译器关于那里的标识符的一些信息。这并不意味着每次程序执行到达声明出现的位置时,编译器都会生成“定义”对象的代码。声明可能有某些方面导致可执行代码,例如自动对象的初始化,编译器会为此生成代码……
标签: c scope language-lawyer storage-duration