考虑该计划
#include <stdio.h>
int main(void) {
for (int curr = 0; curr < 3; curr++) {
int prev;
if (curr) {
printf("%d\n", prev); //valid; prev has 0 or 1
}
prev = curr;
}
}
它有效吗?prev
的生命周期和作用域是什么?
1.在for
循环中将有3个不同的prev
,它们具有生存期和作用域。
不同的prev
可以(但不要求)共享相同的地址。
程序无效。
1.在for
循环中将有3个具有生存期和作用域的prev
。prev
将共享相同的地址,就像用static
定义的一样。
程序有效。
1.将有1个prev
,就好像它是在for
循环之外定义的一样。
程序有效。
- 注:问题源于this answer的讨论 *
4条答案
按热度按时间ntjbwcob1#
1
prev
被视为自动变量,其作用域在循环示例内这意味着在每次迭代中,所有自动变量都被释放,然后在循环再次执行时重新获取。
实际上,
for-loop
的定义是每次执行for语句(在本例中,递增变量)并测试条件,因此即使查看代码,您也可以看到每次循环结束时括号内的范围都已完成。对分配局部变量的地址(或保存该值的寄存器)的任何保证都是无效的。它完全依赖于实现。
9bfwbjaz2#
ISO/IEC 9899:TC3对此非常清楚:
在最初的帖子中,
prev
在循环中有一个常量地址,但在计算时它的值是不确定的。因此,代码表现出未定义的行为。我认为这使得原始帖子(1-4)中的所有答案都不正确。
6tdlim6h3#
答案1正确。
三个不同且截然不同的
prev
,它们不(需要)共享地址或值。在每个循环中,不同的
prev
将被“创建”和“删除”。gcxthw6b4#
当使用C89时,或者当仅使用C的后续版本中提供的循环构造时,代码不可能在对象的生命周期内到达自动对象声明之上的位置。然而,C99增加了使用
goto
将控制从声明下面的点转移到声明对象生命周期内上面的点的能力。我不确定任何非人为程序在多大程度上依赖于这样一个事实,即使用goto
在非VLA对象的声明之上转移控制并不会结束它们的生命周期,但标准要求实现允许这种行为,例如。q
的生存期将在代码进入test
时开始,并在整个函数执行过程中延伸,即使代码分支到声明上方的某个点。如果执行到达一个带有初始化式的声明,则对象的值在那时被赋值;如果它到达一个没有初始化器的声明,对象的值在那时变得不确定,但是如果代码跳过声明,对象将保留其值。