程序有效性;循环内定义的变量的生存期和范围

问题描述

考虑程序

#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. prev循环中将有3个不同的for,它们的生存期和范围。
    不同的prev可以(但不是必须)共享相同的地址。
    程序无效。

  2. prev循环中将有3个for,它们的生存期和范围。
    prev将共享相同的地址,就像使用static定义的一样。
    程序有效。

  3. 将有1个prev,就像它是在for循环之外定义的一样。
    程序有效。

注意:问题是在this answer

上的讨论中提出的

解决方法

在使用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时开始,并且即使代码分支到声明上方的某个点,也会扩展到函数执行的整个过程。如果执行到达带有初始化程序的声明,则此时将分配对象的值;否则,将为对象赋值。如果它到达了没有初始化程序的声明,则该对象的值在那时将变得不确定,但是如果代码跳过该声明,该对象将保留其值。

,

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

enter image description here

在原帖中,prev 在循环中有一个常量地址,但它的值在求值时是不确定的。因此,代码表现出未定义的行为。

我认为这使得原帖 (1-4) 中的所有答案都不正确。

,

1

prev被视为在循环实例内部具有作用域的自动变量

这意味着在每次迭代时都会释放所有自动变量,然后 再次执行循环时重新获取。

实际上,for-loop的定义是for语句每次执行一次(在这种情况下,增加变量)并测试条件, 因此,即使查看代码,您也可以看到方括号内的范围已完成 每次循环结束。

分配局部变量的地址(或保存该值的寄存器)的任何保证均无效。它完全依赖于实现。

,

三个不同且截然不同的prev不需要(不需要)共享地址或值。

在每个循环中,将“创建”和“删除”一个不同的prev