Можно написать большую статью о различии между двумя стилями, с которыми можно столкнуться, людьми, которые всегда инициализируют переменные при объявлении их и людей, которые инициализируют их, когда это необходимо. Я разделяю большой проект с кем-то, кто находится в первой категории, и теперь я определенно больше второго типа. Всегда инициализирующие переменные приводили к более тонким ошибкам и проблемам, чем нет, и я попытаюсь объяснить, почему, вспомнив случаи, которые я нашел. Первый пример:
struct NODE Pop(STACK * Stack)
{
struct NODE node = EMPTY_STACK;
if(Stack && Stack->stackPointer)
node = Stack->node[--Stack->stackPointer];
return node;
}
Это был код, написанный другим парнем. Эта функция является самой горячей функцией в нашем приложении (вы представляете текстовый индекс на 500 000 000 предложений в тройном дереве, стек FIFO используется для обработки рекурсии, поскольку мы не хотим использовать рекурсивные вызовы функций). Это было типично для его стиля программирования из-за его систематической инициализации переменных. Проблема с этим кодом заключалась в скрытии memcpy
инициализации и двух других копий структур (которые, кстати, не звонили в memcpy
gcc странно), поэтому у нас было 3 копии + скрытый вызов функции в самой горячей функции проекта , Переписав его
struct NODE Pop(STACK * Stack)
{
if(Stack && Stack->stackPointer)
return Stack->node[--Stack->stackPointer];
return EMPTY_STACK;
}
только одну копию (и дополнительного пособия на SPARC, где он работает, функция является функцией листа благодаря избегали вызова к memcpy
и не нужно строить новое окно регистров). Таким образом, функция была в 4 раза быстрее.
Еще одна проблема, которую я нашел унцию, но не помню, где именно (так что пример кода, извините). Переменная, которая была инициализирована при объявлении, но использовалась в цикле, с switch
в автомате с конечным состоянием. Проблема в том, что значение инициализации не было одним из состояний автомата, и в некоторых экстремально редких случаях автомат работал неправильно. Удалив инициализатор, предупреждение, выпущенное компилятором, сделало очевидным, что переменная может использоваться до того, как она была правильно инициализирована. Фиксация автомата была легкой. Мораль: защитная инициализация переменной может подавить очень полезное предупреждение о компиляторе.
Заключение: Инициализируйте свои переменные с умом. Выполнение его систематично - это не что иное, как после грузового культа (мой приятель на работе - это худший грузчик, который можно себе представить, он никогда не использует goto, всегда инициализирует переменную, использует множество статических объявлений (это быстрее вы знаете (это на самом деле даже очень медленный на SPARC 64 бит), делает все функции inline
, даже если они имеют 500 строк (с использованием __attribute__((always_inline))
, когда компилятор не хочет)
всего несколько советов, которые идут в одном направлении: используйте минимальную область видимости для ваших переменных. Инициализируйте непосредственно после объявления. Используйте переменные только для одной цели. Используйте const, если вы намерены изменить свою переменную Значение. Основная причина этих подсказок: они улучшают читаемость и r создайте возможность для тонких ошибок при изменении кода. Теперь код может быть без ошибок, не следуя этим подсказкам, но после этого легче сохранить его при каждом изменении кода. –
Определить и инициализировать в одном заявлении, когда это возможно. – 2010-01-11 14:47:07
Нет, инициализируйте свою переменную там, где это уместно. Цикл for более читабельен, когда переменная цикла инициализируется в инструкции for. Ваша переменная могла быть объявлена перед циклом. –