Acredito que me deparei com um caso ambíguo no padrão C em relação ao escopo de objetos declarados na primeira cláusula de um for
loop em comparação com objetos declarados no corpo do loop.
Dado o seguinte código:
for (int i = 1; i < 5; i++) {
int i = 2;
printf("%d ", i);
}
À primeira vista, parece que a declaração i
dentro do corpo do loop está em um escopo interno em comparação ao i
declarado na primeira cláusula do for
loop.
A seção 6.2.1p4 do padrão C23 afirma o seguinte em relação aos identificadores de escopo de bloco :
Se o declarador ou especificador de tipo que declara o identificador aparecer dentro de um bloco ou dentro da lista de declarações de parâmetros em uma definição de função, o identificador tem escopo de bloco , que termina no final do bloco associado
E 6.2.2p6 sobre ligação :
Os seguintes identificadores não têm vinculação: um identificador declarado como algo diferente de um objeto ou uma função; um identificador declarado como um parâmetro de função; um identificador de escopo de bloco para um objeto declarado sem o especificador de classe de armazenamento
extern
.
Portanto, ambos têm escopo de bloco e nenhuma vinculação.
Entretanto, olhando para 6.2.1p6 que diz o seguinte sobre a comparação de escopos:
Dois identificadores têm o mesmo escopo se e somente se seus escopos terminam no mesmo ponto.
E 6.8.5.3p1 sobre a for
declaração diz o seguinte sobre o escopo dos identificadores que declara:
Se a cláusula 1 for uma declaração, o escopo de quaisquer identificadores que ela declara é o restante da declaração e o loop inteiro, incluindo as outras duas expressões; ele é alcançado na ordem de execução antes da primeira avaliação da expressão de controle
Juntando tudo isso, parece que ambos os objetos declarados como i
têm escopos que terminam no mesmo ponto, ou seja, a chave de fechamento do for
loop (ou seja, o fim de "todo o loop") e, portanto, têm o mesmo escopo e, além disso, ambos não têm vinculação.
Isso seria então uma violação de restrição conforme 6.7p3:
Se um identificador não tiver vinculação, não deverá haver mais de uma declaração do identificador (em um declarador ou especificador de tipo) com o mesmo escopo e no mesmo espaço de nomes.
Mas nenhum compilador que testei exibe qualquer diagnóstico.
Intuitivamente, parece que isso deveria ser permitido.
Isso é um defeito no padrão ou estou esquecendo de algo? Existe uma razão específica para que a correspondência de escopo verifique apenas o fim, mas não o começo? A linguagem é a mesma desde C99, quando declarações em for
loops foram introduzidas.