validade do programa; tempo de vida e escopo da variável definida dentro do loop

Oct 25 2020

Considere o programa

#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;
    }
}

É válido?
Qual é a vida útil e o escopo de prev?

  1. Haverá 3 prevs distintos com tempo de vida e escopo dentro do forloop.
    Os prevs distintos podem (mas não são obrigados a) compartilhar o mesmo endereço.
    O programa não é válido.

  2. Haverá 3 prevs com vida útil e escopo dentro do forloop.
    Os prevs irão compartilhar o mesmo endereço, comportando-se como se definidos com static.
    O programa é válido.

  3. Haverá 1 prev, como se fosse definido fora do forloop.
    O programa é válido.

Nota: pergunta originada durante a discussão sobre esta resposta

Respostas

1 supercat Oct 25 2020 at 16:31

Ao usar o C89, ou ao usar apenas os construtos de loop fornecidos em versões posteriores do C, é impossível para o código chegar a um local acima da declaração de um objeto automático durante o tempo de vida do objeto. C99, no entanto, adicionou a capacidade de usar gotopara transferir o controle de um ponto abaixo de uma declaração para um ponto acima dentro do tempo de vida do objeto declarado por meio disso. Não tenho certeza de até que ponto quaisquer programas não planejados dependem do fato de que usar gotopara transferir o controle acima da declaração de um objeto não-VLA não encerra sua vida útil, mas o Padrão exige que as implementações levem em consideração tal comportamento, por exemplo,

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;
}

o tempo de vida de qcomeçaria quando o código fosse inserido teste se estenderia por toda a execução da função, mesmo se o código se ramificasse para um ponto acima da declaração. Se a execução atinge uma declaração com um inicializador, o valor do objeto é atribuído naquele momento; se atingir uma declaração sem um inicializador, o valor do objeto se tornará indeterminado naquele momento, mas se o código pular a declaração, o objeto reterá seu valor.

pmg Oct 25 2020 at 16:20

Três prevs diferentes e distintos que não (precisam) compartilhar endereço ou valor.

Em cada loop, um diferente prevserá "criado" e "excluído".

BarakFriedman Oct 25 2020 at 16:13

1

prev é tratada como uma variável automática que tem um escopo dentro da instância do loop

Isso significa que, a cada iteração, todas as variáveis ​​automáticas são liberadas e readquiridas quando o loop é executado novamente.

Na verdade, a definição de for-loopé que a instrução for é executada a cada vez (incrementando a variável, neste caso) e testando a condição, portanto, mesmo olhando para o código, você pode ver que o escopo entre colchetes termina cada vez que o loop termina.

Qualquer garantia do endereço no qual a variável local é alocada (ou um registro contendo o valor) é nula. É totalmente dependente da implementação.