Um bloco é uma lista de instruções a serem executadas. Exemplos de onde os blocos aparecem em C são após uma declaração while e em if
while( boolean expression)
statement OR block
if (boolean expression)
statement OR block
C também permite que um bloco seja aninhado em um bloco. Eu posso usar isso para reutilizar nomes de variáveis, suponha que eu realmente goste de 'x'
int x = 0;
while (x < 10)
{
{
int x = 5;
printf("%d",x)
}
x = x+1;
}
imprimirá o número 5 dez vezes. Acho que pude ver situações em que é desejável manter o número de nomes de variáveis baixo. Talvez em expansão macro. No entanto, não vejo nenhum motivo difícil para precisar desse recurso. Alguém pode me ajudar a entender os usos desse recurso, fornecendo alguns idiomas onde ele é usado.
Respostas:
A idéia não é manter o número de nomes de variáveis baixo ou incentivar a reutilização de nomes, mas limitar o escopo das variáveis. Se você tem:
em seguida, o escopo de
y
se limita ao bloco, o que significa que você pode esquecê-lo antes ou depois do bloco. Você vê isso usado com mais frequência em conexão com loops e condicionais. Você também vê isso com mais frequência em linguagens do tipo C, como C ++, onde uma variável que sai do escopo causa sua destruição.fonte
Porque antigamente, em C, novas variáveis só podiam ser declaradas em um novo bloco.
Dessa forma, os programadores poderiam introduzir novas variáveis no meio de uma função sem vazá-la e minimizar o uso da pilha.
Nos otimizadores de hoje, é inútil e um sinal de que você precisa considerar a extração do bloco em sua própria função.
Em uma instrução switch, é útil colocar os casos em seus próprios blocos para evitar a declaração dupla.
No C ++, é muito útil, por exemplo, para os protetores de bloqueio RAII e garantir que os destruidores executem o bloqueio de liberação quando a execução estiver fora do escopo e ainda fizer outras coisas fora da seção crítica.
fonte
Eu não consideraria isso blocos "arbitrários". Não é um recurso destinado tanto ao uso do desenvolvedor, mas a maneira como C usa blocos permite que a mesma construção seja usada em vários locais com a mesma semântica. Um bloco (em C) é um novo escopo e as variáveis que o deixam são eliminadas. Isso é uniforme, independentemente de como o bloco é usado.
Em outros idiomas, esse não é o caso. Isso tem a vantagem de permitir menos abusos, como você mostra, mas a desvantagem que os blocos se comportam de maneira diferente, dependendo do contexto em que estão.
Eu raramente vi blocos autônomos usados em C ou C ++ - geralmente quando há uma grande estrutura ou um objeto que representa uma conexão ou algo que você deseja forçar a destruição. Geralmente, essa é uma dica de que sua função está fazendo muitas coisas e / ou é muito longa.
fonte
Você precisa entender que os princípios de programação que parecem óbvios agora nem sempre eram assim. As melhores práticas de C dependem muito da idade dos seus exemplos. Quando C foi introduzido pela primeira vez, dividir seu código em pequenas funções foi considerado muito ineficiente. Dennis Ritchie basicamente mentiu e disse que as chamadas de função eram realmente eficientes em C (não eram na época), que foi o que levou as pessoas a usá-las mais, embora os programadores de C de alguma forma nunca tenham passado completamente por uma cultura de otimização prematura.
ele é uma boa prática de programação ainda hoje para limitar o escopo de suas variáveis tão pequeno quanto possível. Atualmente, normalmente fazemos isso criando uma nova função, mas se as funções são consideradas caras, a introdução de um novo bloco é uma maneira lógica de limitar seu escopo sem a sobrecarga de uma chamada de função.
No entanto, eu comecei a programar em C há mais de 20 anos, quando você tinha que declarar todas as suas variáveis no topo de um escopo, e não me lembro de sombreamento de variáveis como se alguma vez fosse considerado um bom estilo. Redeclarando em dois blocos, um após o outro, como em uma instrução switch, sim, mas não na sombra. Talvez se a variável já foi usado e o nome específico foi altamente idiomática para a API que você está chamando, como
dest
esrc
emstrcpy
, por exemplo.fonte
Blocos arbitrários são úteis para introduzir variáveis intermediárias que são usadas apenas em casos especiais de um cálculo.
Este é um padrão comum na computação científica, onde os procedimentos numéricos geralmente:
Por causa do segundo ponto, é útil introduzir variáveis temporárias de escopo limitado, o que é obtido com o uso de um bloco arbitrário ou com a introdução de uma função auxiliar.
Embora a introdução de uma função auxiliar possa parecer um acéfalo ou uma prática recomendada a seguir cegamente, na verdade existem poucos benefícios em fazê-lo nessa situação específica.
Como existem muitos parâmetros e quantidades intermediárias, queremos introduzir uma estrutura para transmiti-los à função auxiliar.
Mas, como queremos ser conseqüentes com nossas práticas, não apresentaremos apenas uma função auxiliar, mas várias. Portanto, se introduzimos estruturas ad-hoc que transmitem parâmetros para cada função, que introduzem muitas sobrecargas de código para mover parâmetros para frente e para trás, ou introduzimos uma que governará toda a estrutura da planilha, que contém todas as nossas variáveis, mas parece um pacote de bits sem consistência, onde a qualquer momento apenas a metade dos parâmetros tem um significado interessante.
Portanto, essas estruturas auxiliares são tipicamente pesadas e usá-las significa escolher entre inchar o código ou introduzir uma abstração cujo escopo é muito amplo e enfraquece o significado do programa, em vez de fortalecê-lo .
A introdução de funções auxiliares pode facilitar o teste de unidade do programa, introduzindo uma granularidade de teste mais fina, mas combinando o teste de unidade para procedimentos não de baixo nível e testes de regressão na forma de comparações (com número) de traços numéricos dos procedimentos, um trabalho igualmente bom .
fonte
Em geral, a reutilização de nomes de variáveis dessa maneira causa muita confusão para futuros leitores do seu código. É melhor simplesmente nomear a variável interna de outra forma. De fato, a linguagem C # proíbe especificamente o uso de variáveis dessa maneira.
Pude ver como o uso de blocos aninhados em expansões de macro seria útil para evitar colisões de nomes variáveis.
fonte
É para o escopo de coisas que normalmente não têm escopo nesse nível. Isso é extremamente raro e, em geral, a refatoração é uma escolha melhor, mas eu já o encontrei uma ou duas vezes no passado em declarações de opção:
Quando você considera a manutenção, a refatoração deve ser equilibrada com todas as implementações seguidas, desde que cada uma tenha apenas algumas linhas. Pode ser mais fácil tê-los todos juntos, em vez de uma lista de nomes de funções.
No meu caso, se bem me lembro, a maioria dos casos eram pequenas variações do mesmo código - exceto que um era idêntico ao outro, apenas com pré-processamento extra. Uma opção acabou sendo a forma mais simples para o código, e o escopo extra permitiu o uso de variáveis locais extras com as quais ele e outros casos não precisaram se preocupar (como nomes de variáveis que se sobrepõem acidentalmente a uma definida antes da opção, mas usado mais tarde).
Observe que a instrução switch é simplesmente o uso que eu encontrei. Tenho certeza de que isso também pode ser aplicado em outros lugares, mas não me lembro de vê-los usados dessa maneira.
fonte