C语言 程序有效性循环内定义的变量的生存期和作用域

q0qdq0h2  于 2023-05-16  发布在  其他
关注(0)|答案(4)|浏览(142)

考虑该计划

#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循环之外定义的一样。
程序有效。

ntjbwcob

ntjbwcob1#

1
prev被视为自动变量,其作用域在循环示例内
这意味着在每次迭代中,所有自动变量都被释放,然后在循环再次执行时重新获取。
实际上,for-loop的定义是每次执行for语句(在本例中,递增变量)并测试条件,因此即使查看代码,您也可以看到每次循环结束时括号内的范围都已完成。
对分配局部变量的地址(或保存该值的寄存器)的任何保证都是无效的。它完全依赖于实现。

9bfwbjaz

9bfwbjaz2#

ISO/IEC 9899:TC3对此非常清楚:

在最初的帖子中,prev在循环中有一个常量地址,但在计算时它的值是不确定的。因此,代码表现出未定义的行为。
我认为这使得原始帖子(1-4)中的所有答案都不正确。

6tdlim6h

6tdlim6h3#

答案1正确。
三个不同且截然不同的prev,它们不(需要)共享地址或值。
在每个循环中,不同的prev将被“创建”和“删除”。

gcxthw6b

gcxthw6b4#

当使用C89时,或者当仅使用C的后续版本中提供的循环构造时,代码不可能在对象的生命周期内到达自动对象声明之上的位置。然而,C99增加了使用goto将控制从声明下面的点转移到声明对象生命周期内上面的点的能力。我不确定任何非人为程序在多大程度上依赖于这样一个事实,即使用goto在非VLA对象的声明之上转移控制并不会结束它们的生命周期,但标准要求实现允许这种行为,例如。

void test(void)
{
  int pass=0;
  int temp;
  int *p;
  int result;

  firstPass:
    if (pass)
    {
      temp = *p;
      goto secondPass;
    }
    pass++;
    int q=1;
    p=&q;
    q++;
    goto firstPass;          
  secondPass:
    return temp + q;
}

q的生存期将在代码进入test时开始,并在整个函数执行过程中延伸,即使代码分支到声明上方的某个点。如果执行到达一个带有初始化式的声明,则对象的值在那时被赋值;如果它到达一个没有初始化器的声明,对象的值在那时变得不确定,但是如果代码跳过声明,对象将保留其值。

相关问题