Переменные определены и назначены одновременно - PullRequest
0 голосов
/ 11 июня 2009

Презентация стиля кодирования, которую я недавно посещал в офисе, настаивала на том, что переменные НЕ должны назначаться (по умолчанию), когда они определены. Вместо этого им следует назначить значение по умолчанию непосредственно перед их использованием. Итак, что-то вроде

int a = 0;

надо нахмуриться.

Очевидно, что пример 'int' является упрощенным, но то же самое следует для других типов, таких как указатели и т. Д.

Кроме того, было также отмечено, что C99-совместимые компиляторы теперь выдают предупреждение в вышеупомянутом случае.

Вышеупомянутый подход выглядит полезным для меня только для структур, т. Е. Вы устанавливаете их только перед использованием. Это будет эффективно, если структура используется (или заполнена) только в участке ошибки.

Для всех остальных случаев определение и присвоение значения по умолчанию целесообразно, так как я столкнулся с множеством ошибок из-за неинициализированных указателей как при написании, так и при поддержке кода. Кроме того, я полагаю, что C ++ через конструкторы также поддерживает тот же подход, то есть определяет и назначает.

Мне интересно, почему (если) стандарт C99 не любит определять и присваивать. Есть ли у них значительная заслуга в том, чтобы защищать презентацию в стиле кодирования?

Ответы [ 5 ]

1 голос
/ 19 июня 2009

Обычно я рекомендую инициализировать переменные, когда они определены, если значение, которое они должны иметь, известны, и оставить переменные неинициализированными, если значение не известно. В любом случае, поместите их настолько близко к их использованию, насколько позволяют правила области видимости.

Вместо этого им следует присвоить значение по умолчанию непосредственно перед их использованием.

Обычно вам вообще не следует использовать значение по умолчанию. В C99 вы можете смешивать код и объявления, поэтому нет смысла определять переменную, прежде чем присваивать ей значение. Если вы знаете значение, которое оно должно принимать, то нет смысла иметь значение по умолчанию.

Кроме того, было также упомянуто, что C99-совместимые компиляторы теперь выдают предупреждение в вышеупомянутом случае.

Не для того случая, который вы показываете - вы не получите предупреждение за наличие int x = 0;. Я сильно подозреваю, что кто-то перепутал это. Компиляторы предупреждают, если вы используете переменную без присвоения ей значения, и если у вас есть:

... some code ...

int x;

if ( a )
    x = 1;
else if ( b )
    x = 2;
// oops, forgot the last case else x = 3;

return x * y;

тогда вы получите предупреждение, что x может использоваться без инициализации, по крайней мере, с помощью gcc.

Вы не получите предупреждение, если назначите значение для x до if, но не имеет значения, выполняется ли присвоение как инициализатор или как отдельный оператор.

Если у вас нет особых причин назначать значение дважды для двух ветвей, нет смысла назначать значение по умолчанию для x первым, так как это останавливает компилятор, предупреждающий вас о том, что вы закрыли каждую ветвь.

1 голос
/ 11 июня 2009

В C99 нет нет такого требования (или даже известной мне директивы), и компилятор не предупреждает вас об этом. Это просто вопрос стиля.

Что касается стиля кодирования, я думаю, вы восприняли все слишком буквально. Например, ваше утверждение верно в следующем случае ...

int i = 0;

for (; i < n; i++)
        do_something(i);

... или даже в ...

int i = 1;

[some code follows here]

while (i < a)
        do_something(i);

... но есть и другие случаи, которые, на мой взгляд, лучше обрабатываются с помощью раннего "объявления и назначения". Рассмотрим структуры, построенные в стеке, или различные конструкции ООП, например:

struct foo {
        int bar;

        void *private;
};

int my_callback(struct foo *foo)
{
        struct my_struct *my_struct = foo->private;

        [do something with my_struct]

        return 0;
}

Или как в (инициализаторы структуры C99):

void do_something(int a, int b, int c)
{
        struct foo foo = {
                .a        = a,
                .b        = b + 1,
                .c        = c / 2,
        };

        write_foo(&foo);
}
0 голосов
/ 11 июня 2009

Я видел так много ошибок из-за неинициализированных указателей, что я всегда рекомендовал объявлять каждую переменную с NULL_PTR и каждый примитив с некоторым недопустимым значением / значением по умолчанию.

Поскольку я работаю с ОСРВ и высокопроизводительными, но низкоресурсными системами, вполне возможно, что используемые нами компиляторы не улавливают неинициализированное использование. Хотя я сомневаюсь, что на современные компиляторы можно также положиться на 100%.

В больших проектах, где широко используются макросы, я видел редкие сценарии, когда даже Kloclwork / Purify не удалось найти неинициализированное использование.

Так что я говорю, придерживайтесь его, пока вы используете простой старый C / C ++.

Современные языки, такие как .Net, могут гарантировать инициализацию переменных или выдавать ошибку компилятора при использовании неинициализированной переменной. Следующая ссылка выполняет анализ производительности и подтверждает, что производительность .NET составляет 10-20%. Анализ достаточно подробно и хорошо объяснен.

http://www.codeproject.com/KB/dotnet/DontInitializeVariables.aspx

0 голосов
/ 11 июня 2009

Я считаю очень полезным предварительно назначать переменным некоторые данные по умолчанию, чтобы мне не приходилось делать (столько же) нулевых проверок в коде.

0 голосов
/ 11 июня 2009

Я в чем-то согласен с этим советом, хотя я не совсем уверен, что стандарт о нем что-то говорит, и я очень сомневаюсь, что часть предупреждений компилятора верна.

Дело в том, что современные компиляторы могут и действительно обнаруживают использование неинициализированных переменных. Если при инициализации вы установите для переменных значения по умолчанию, вы потеряете это обнаружение. И значения по умолчанию тоже могут вызывать ошибки; конечно, в случае вашего примера, int a = 0;. Кто сказал, что 0 является подходящим значением для a?

В 1990-х совет был бы неправильным. В наше время это правильно.

...