Como foi observado, existem duas escolas de pensamento sobre isso.
1) Declare tudo no topo das funções porque o ano é 1987.
2) Declare o mais próximo do primeiro uso e no menor escopo possível.
Minha resposta para isso é FAÇA AMBOS! Deixe-me explicar:
Para funções longas, 1) torna a refatoração muito difícil. Se você trabalha em uma base de código em que os desenvolvedores são contrários à ideia de sub-rotinas, você terá 50 declarações de variáveis no início da função e algumas delas podem ser apenas um "i" para um loop for muito parte inferior da função.
Portanto, desenvolvi a declaração no topo do TEPT e tentei fazer a opção 2) religiosamente.
Voltei à opção um por causa de uma coisa: funções curtas. Se suas funções forem curtas o suficiente, você terá poucas variáveis locais e, como a função é curta, se você as colocar no topo da função, elas ainda estarão próximas ao primeiro uso.
Além disso, o antipadrão de "declarar e definir como NULL" quando você deseja declarar na parte superior, mas ainda não fez alguns cálculos necessários para a inicialização, é resolvido porque as coisas que você precisa inicializar provavelmente serão recebidas como argumentos.
Então, agora, meu pensamento é que você deve declarar no topo das funções e o mais próximo possível do primeiro uso. Então AMBOS! E a maneira de fazer isso é com sub-rotinas bem divididas.
Mas se você estiver trabalhando em uma função longa, coloque as coisas mais próximas do primeiro uso, pois assim será mais fácil extrair métodos.
Minha receita é essa. Para todas as variáveis locais, pegue a variável e mova sua declaração para o final, compile e mova a declaração imediatamente antes do erro de compilação. Esse é o primeiro uso. Faça isso para todas as variáveis locais.
int foo = 0;
<code that uses foo>
int bar = 1;
<code that uses bar>
<code that uses foo>
Agora, defina um bloco de escopo que seja iniciado antes da declaração e mova o final até o programa compilar
{
int foo = 0;
<code that uses foo>
}
int bar = 1;
<code that uses bar>
>>> First compilation error here
<code that uses foo>
Isso não é compilado porque há mais código que usa foo. Podemos notar que o compilador foi capaz de passar pelo código que usa bar porque não usa foo. Neste ponto, existem duas opções. O mecânico é apenas mover o "}" para baixo até compilar, e a outra opção é inspecionar o código e determinar se a ordem pode ser alterada para:
{
int foo = 0;
<code that uses foo>
}
<code that uses foo>
int bar = 1;
<code that uses bar>
Se a ordem puder ser alterada, provavelmente é isso que você deseja, pois reduz a vida útil dos valores temporários.
Outra coisa a ser observada: o valor de foo precisa ser preservado entre os blocos de código que o utilizam, ou poderia ser apenas um foo diferente em ambos. Por exemplo
int i;
for(i = 0; i < 8; ++i){
...
}
<some stuff>
for(i = 3; i < 32; ++i){
...
}
Essas situações precisam mais do que meu procedimento. O desenvolvedor precisará analisar o código para determinar o que fazer.
Mas o primeiro passo é encontrar o primeiro uso. Você pode fazer isso visualmente, mas às vezes é mais fácil excluir a declaração, tentar compilar e colocá-la novamente acima do primeiro uso. Se esse primeiro uso estiver dentro de uma instrução if, coloque-o lá e verifique se ele compila. O compilador identificará outros usos. Tente criar um bloco de escopo que inclua os dois usos.
Depois que essa parte mecânica é concluída, fica mais fácil analisar onde estão os dados. Se uma variável for usada em um grande bloco de escopo, analise a situação e veja se você está apenas usando a mesma variável para duas coisas diferentes (como um "i" que é usado por duas para loops). Se os usos não estiverem relacionados, crie novas variáveis para cada um desses usos não relacionados.