Должен объявить прототип функции в C?

Я отчасти новичок в C (у меня есть предшествующий Java, С# и некоторый опыт на С++). В C, нужно ли объявлять прототип функции или может компилироваться код без него? Это хорошая практика программирования? Или это просто зависит от компилятора? (Я запускаю Ubuntu 9.10 и использую компилятор GNU C или gcc в среде Code:: Blocks IDE)

Ответ 1

В ANSI C (что означает C89 или C90), вам не нужно объявлять прототип функции; однако использовать их лучше всего. Единственная причина, по которой стандарт позволяет вам не использовать их, - это обратная совместимость с очень старым кодом.

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

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

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

В C99 или C11 стандартное C требует объявления функции в области до вызова любой функции. Многие компиляторы не применяют это ограничение на практике, если вы не заставляете их делать это.

Ответ 2

Никогда не требуется объявлять прототип для функции в C, ни в "старом" C (включая C89/90), ни в новом C (C99). Тем не менее, существует значительная разница между C89/90 и C99 в отношении объявлений функций.

В C89/90 нет необходимости объявлять какую-либо функцию вообще. Если функция не объявлена ​​в точке вызова, компилятор "угадывает" (записывает) декларацию неявно из типов аргументов, переданных в вызове, и предполагает, что тип возврата int.

Например

int main() {
  int i = foo(5); 
  /* No declaration for `foo`, no prototype for `foo`.
     Will work in C89/90. Assumes `int foo(int)` */

  return 0;
}

int foo(int i) {
  return i;
}

В C99 каждая функция, которую вы вызываете, должна быть объявлена ​​перед точкой вызова. Тем не менее, по-прежнему нет необходимости заявлять об этом с помощью прототипа. Также будет работать декларация, отличная от прототипа. Это означает, что в C99 правило "неявное int" больше не работает (для предполагаемых типов возвращаемых функций в этом случае), но типы параметров все еще можно угадать из типов аргументов, если функция объявлена ​​без прототипа.

Предыдущий пример не будет компилироваться в C99, так как foo не объявляется в точке вызова. Тем не менее, вы можете добавить объявление без прототипа

int foo(); /* Declares `foo`, but still no prototype */

int main() {
  int i = foo(5); 
  /* No prototype for `foo`, although return type is known. 
     Will work in C99. Assumes `int foo(int)` */

  return 0;
}
...

и введите действительный код C99.

Тем не менее, всегда рекомендуется зарекомендовать прототип функции, прежде чем вы ее назовете.

Дополнительная заметка: Я сказал выше, что никогда не требуется объявлять прототип функции. На самом деле для некоторых функций это требование. Чтобы правильно вызвать переменную функцию в C (printf например), функция должна быть объявлена ​​прототипом до точки вызова. В противном случае поведение undefined. Это относится как к C89/90, так и к C99.

Ответ 3

это не обязательно, если функция определена до ее использования.

Ответ 4

Это не требуется, но плохой практикой не использовать прототипы.

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

Без прототипов это возможно:

// file1.c
void doit(double d)
{
    ....
}

int sum(int a, int b, int c)
{
    return a + b + c;
}

и это:

// file2.c

// In C, this is just a declaration and not a prototype
void doit();
int sum();

int main(int argc, char *argv[])
{
    char idea[] = "use prototypes!";

    // without the prototype, the compiler will pass a char *
    // to a function that expects a double
    doit(idea);

    // and here without a prototype the compiler allows you to
    // call a function that is expecting three argument with just
    // one argument (in the calling function, args b and c will be
    // random junk)
    return sum(argc);
}

Ответ 5

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

Ответ 6

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

Ответ 7

Вы должны поместить объявления функций в файл заголовка (X.h) и определение в исходный файл (X.c). Тогда другие файлы могут #include "X.h" и вызвать функцию.

Ответ 8

Прототип функции не является обязательным в соответствии со стандартом C99.

Ответ 9

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

Сказав, что очевидно, что правильное объявление функций с прототипами является гораздо лучшей практикой.

Ответ 10

Выберите "Меню параметров", а затем выберите "Компилятор". С++ Опции. В появившемся диалоговом окне выберите "CPP всегда" в разделе "Использовать параметры компилятора С++". Снова выберите "Меню параметров", затем выберите "Окружающая среда | Редактор. Убедитесь, что расширение по умолчанию - "C", а не "CPP.