лучшие практики по приоритету объявления переменных и обработки ошибок в C - PullRequest
2 голосов
/ 13 июня 2010

есть ли преимущество в одном из следующих двух подходов по сравнению с другим?

здесь сначала проверяется, удастся ли вообще fopen и , затем все объявления переменных принимаютместо, чтобы убедиться, что они не выполняются, так как они не должны были

void func(void) {
    FILE *fd;

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    int a, b, c;
    float d, e, f;
    /* variable declarations */

    /* remaining code */
}

это как раз наоборот.все объявления переменных имеют место, даже если fopen терпит неудачу

void func(void) {
    FILE *fd;
    int a, b, c;
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */        
}

, дает ли второй подход какие-либо дополнительные стоимость , когда fopen терпит неудачу?хотел бы услышать ваши мысли!

Ответы [ 5 ]

4 голосов
/ 13 июня 2010

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

1 голос
/ 13 июня 2010

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

Например:

void func(const char * filename) {
    FILE *fd;
    int a, b, c;
    size_t z = strlen(filename);
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen(filename, "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */    
    /* Some code that uses z */
}

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

1 голос
/ 13 июня 2010

Распределение стековых переменных для всех переменных в функции в одной и той же области видимости, вероятно, происходит в верхней части вашей функции в обоих случаях, поэтому любой метод подходит.

1 голос
/ 13 июня 2010

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

0 голосов
/ 13 июня 2010

Это не должно иметь никакого значения, но вы всегда можете сравнить выходные данные сборки двух версий, чтобы убедиться!

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

Однако в C ++ могут возникнуть некоторые проблемы при переходе через инициализацию (которую вы не делаете в коде в своем примере)но C ++ гораздо сложнее рассуждать.

...