Переменные, определенные и назначенные одновременно

StackOverflow https://stackoverflow.com/questions/979454

Вопрос

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

int a = 0;

на это следует смотреть неодобрительно.

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

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

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

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

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

Это было полезно?

Решение

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

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

Обычно вам вообще не следует использовать значение по умолчанию.В 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, поскольку это останавливает компилятор, предупреждающий вас о том, что вы охватили каждую ветвь.

Другие советы

Там есть НЕТ такое требование (или даже руководство, о котором я знаю) в 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);
}

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

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

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

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

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

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

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

Поэтому я советую придерживаться этого до тех пор, пока вы используете обычный старый C / C ++.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top