Как уже отмечалось, есть две школы мысли об этом.
1) Объявите все наверху функций, потому что это 1987.
2) Объявлять наиболее близким к первому использованию и в наименьшем возможном объеме.
Мой ответ на этот вопрос - ОБА! Позвольте мне объяснить:
Для длинных функций 1) делает рефакторинг очень трудным. Если вы работаете в кодовой базе, где разработчики против идеи подпрограмм, то у вас будет 50 объявлений переменных в начале функции, и некоторые из них могут быть просто «i» для цикла for, который находится на самом нижняя часть функции.
Исходя из этого, я разработал ПТСР на самом верху и попытался сделать вариант 2) неукоснительно.
Я вернулся к первому варианту из-за одной вещи: короткие функции. Если ваши функции достаточно короткие, у вас будет мало локальных переменных, и поскольку функция короткая, если вы поместите их в верхнюю часть функции, они все равно будут близки к первому использованию.
Кроме того, устранен шаблон «объявить и установить значение NULL», когда вы хотите объявить сверху, но вы не сделали некоторые вычисления, необходимые для инициализации, устранена, потому что вещи, которые вам нужно инициализировать, скорее всего будут получены аргументы.
Так что теперь я думаю, что вы должны объявить в верхней части функций и как можно ближе к первому использованию. Так ОБА! И способ сделать это с помощью хорошо разделенных подпрограмм.
Но если вы работаете с длинной функцией, то поставьте вещи ближе всего к первому использованию, потому что таким образом будет легче извлечь методы.
Мой рецепт такой. Для всех локальных переменных возьмите переменную и переместите ее декларацию вниз, скомпилируйте, затем переместите декларацию непосредственно перед ошибкой компиляции. Это первое использование. Сделайте это для всех локальных переменных.
int foo = 0;
<code that uses foo>
int bar = 1;
<code that uses bar>
<code that uses foo>
Теперь определите блок области видимости, который начинается перед объявлением, и перемещайте конец до тех пор, пока программа не скомпилирует
{
int foo = 0;
<code that uses foo>
}
int bar = 1;
<code that uses bar>
>>> First compilation error here
<code that uses foo>
Это не компилируется, потому что есть еще некоторый код, который использует foo. Мы можем заметить, что компилятор смог пройти через код, который использует bar, потому что он не использует foo. На данный момент, есть два варианта. Механический - просто сдвинуть "}" вниз, пока он не скомпилируется, а другой выбор - проверить код и определить, можно ли изменить порядок на:
{
int foo = 0;
<code that uses foo>
}
<code that uses foo>
int bar = 1;
<code that uses bar>
Если порядок можно переключать, это, вероятно, то, что вы хотите, потому что это сокращает срок службы временных значений.
Еще один момент, на который следует обратить внимание: нужно ли сохранять значение foo между блоками кода, которые его используют, или это может быть другой foo в обоих. Например
int i;
for(i = 0; i < 8; ++i){
...
}
<some stuff>
for(i = 3; i < 32; ++i){
...
}
Эти ситуации нуждаются не только в моей процедуре. Разработчик должен будет проанализировать код, чтобы определить, что делать.
Но первый шаг - это найти первое применение. Вы можете сделать это визуально, но иногда проще просто удалить объявление, попытаться скомпилировать и просто вернуть его выше первого использования. Если это первое использование внутри оператора if, поместите его туда и проверьте, компилируется ли оно. Затем компилятор определит другие варианты использования. Попробуйте создать блок области действия, который охватывает оба варианта использования.
После того, как эта механическая часть выполнена, становится легче анализировать, где находятся данные. Если переменная используется в большом блоке области действия, проанализируйте ситуацию и посмотрите, используете ли вы одну и ту же переменную для двух разных вещей (например, «i», которое используется для двух для циклов for). Если использование не связано, создайте новые переменные для каждого из этих не связанных применений.