Por exemplo, temos o seguinte código:
#include <stdio.h>
int main(void)
{
int n = 4;
{
n++;
}
printf("%d\n",n);
return 0;
}
Como o bloco interno vê a variável n? Como o padrão da linguagem C explica isso? Há algum tempo venho procurando uma resposta para essa pergunta. Na minha opinião, a resposta é a seguinte: em C17, temos (6.8 #3):
Um bloco permite que um conjunto de declarações e instruções seja agrupado em uma unidade sintática. Os inicializadores de objetos com duração de armazenamento automática e os declaradores de array de comprimento variável de identificadores comuns com escopo de bloco são avaliados e os valores são armazenados nos objetos (incluindo o armazenamento de um valor indeterminado em objetos sem um inicializador) cada vez que a declaração é alcançada, na ordem de execução, como se fosse uma instrução, e dentro de cada declaração na ordem em que os declaradores aparecem.
Se você não considerar os inicializadores, descobrirá que um bloco é composto apenas de algumas instruções. Usamos um bloco para avaliar todos esses operadores como uma unidade sintática. Em outras palavras, se você remover os caracteres {} do bloco, esses serão os mesmos operadores e o resultado será exatamente o mesmo, mas esses operadores não serão avaliados em uma unidade sintática:
#include <stdio.h>
int main(void)
{
int n = 4;
n++; // same effect but without {}
printf("%d\n",n);
return 0;
}
Também temos (6.2.1 # 4):
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 terá escopo de bloco, que termina no final do bloco associado.
A partir disso entendemos que n tem um escopo de bloco.
Se combinarmos tudo isso, descobrimos que n é incrementado como se o operador de incremento nunca tivesse aparecido no bloco interno.
Esta resposta está correta? Se não, explique o porquê. E cite um parágrafo do padrão da linguagem C.
Porque o bloco interno é parte do bloco externo (ou seja, o corpo da função neste caso).
A seção 6.2.1p4 do padrão C descreve o escopo do bloco :
Portanto, o escopo de
n
é o bloco que é o corpo damain
função. Isso inclui o bloco que contém an++
instrução.Observe que o seguinte, que pode parecer mais familiar, é o mesmo em termos de escopo:
Neste caso, o bloco é a parte "instrução" da
if
instrução e, como acima, este bloco é um escopo "interno" ao corpo da função.Isto é uma questão de escopo:
(C23 6.2.1/2)
Você já citou a seção (de 6.2.1/4) que (em grande parte) define o escopo de variáveis com escopo de bloco, como a sua
n
. Ela termina no final do bloco envolvente mais interno. Todo o bloco aninhado está dentro desse escopo, portanto,n
é visível lá.Sim, no seu exemplo. Um bloco vazio como o seu não faz muita coisa, embora possa ser útil limitar o escopo das variáveis declaradas nele.
if
Mas você não pode remover livremente as chaves nos usos mais comuns de blocos. Um bloco é obrigatório para corpos de função. Blocos com múltiplas instruçõeselse
e corpos de laço teriam significados diferentes se as chaves de seus blocos fossem removidas. Por exemplo, isto...... produz uma saída diferente desta:
E, de fato, reduzir o risco de introduzir tais erros é uma das razões para a regra de estilo comum de que
if
,else
e corpos de loop devem sempre ser blocos, mesmo quando o bloco contém apenas uma única instrução.Mais ou menos. Não está claro qual seria a alternativa. Mas sim, a avaliação de
n++
dentro do bloco tem o mesmo efeito que sem o bloco imediatamente envolvente. Se quiser diferente, você pode declarar um diferenten
dentro do bloco.Do Padrão C23 (6.2.1 Escopos de identificadores, nomes de tipos e literais compostos)
e
No seu exemplo, a variável
n
não está oculta no escopo do bloco interno. Se, em vez disso, você escrevesse, por exemploentão a variável
n
declarada no escopo do bloco interno ocultaria a variável com o mesmo nome declarada no escopo externo.Ou um exemplo mais interessante
Neste caso você obterá o mesmo resultado do seu programa original
A propósito, você pode reintroduzir em um escopo interno uma variável que tem escopo de arquivo e estava oculta em algum bloco envolvente do escopo do bloco interno.
Olha Você aqui.