Должны объявить прототип функции в C? [дубликат]

этот вопрос уже есть ответ здесь:

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

10 ответов


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

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

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

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

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


никогда не требуется объявлять прототип для функции в 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 "implicit 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.

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

дополнительно: я сказал выше, что это никогда не требуется объявлять прототип функции. Фактически, для некоторых функций это требование. Для того, чтобы правильно называть variadic функция в C () функция должна быть объявлена С прототипом перед точкой вызова. В противном случае поведение не определено. Это касается как С89/90 и C99.


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


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

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

без прототипов можно иметь следующее:

// 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);
}

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


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


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


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


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

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


выберите меню "Параметры", а затем выберите " компилятор / C++ Опционы.’ В появившемся диалоговом окне выберите "CPP always". в параметрах " использовать компилятор C++". Снова выберите ‘меню’ и выберите ‘среды | Редактор.’ Убедитесь, что расширение по умолчанию - "C", а не ‘СРР.’