Этот вопрос уже имеет ответ здесь:
Я довольно плохо знаком с C (у меня есть предшествующий Java, C# и некоторый опыт C++). В C действительно ли необходимо объявить прототипа функции, или код может скомпилировать без него? Это - хорошая практика программирования, чтобы сделать так? Или это просто зависит от компилятора? (Я запускаю Ubuntu 9.10 и использую компилятор C GNU или gcc, в соответствии с Кодом:: Блоки IDE)
В ANSI C (то есть C89 или C90) вам не нужно объявлять прототип функции; однако их рекомендуется использовать. Единственная причина, по которой стандарт позволяет не использовать их, - это обратная совместимость с очень старым кодом.
Если у вас нет прототипа, и вы вызываете функцию, компилятор выведет прототип из параметров, которые вы передаете функции. Если вы объявите функцию позже в том же модуле компиляции, вы получите ошибку компиляции, если подпись функции отличается от того, что предположил компилятор.
Хуже того, если функция находится в другом модуле компиляции, невозможно получить ошибку компиляции, поскольку без прототипа нет возможности проверить. В этом случае, если компилятор ошибается, вы можете получить неопределенное поведение, если вызов функции помещает в стек разные типы, чем ожидает функция.
Соглашение заключается в том, чтобы всегда объявлять прототип в файле заголовка, имя которого совпадает с именем исходного файла, содержащего функцию.
В C99 или C11 стандартный C требует объявления функции в области видимости перед вызовом любой функции. Многие компиляторы не применяют это ограничение на практике, если вы не принуждаете их к этому.
Вы должны поместить объявления функций в файл заголовка (X.h), а определение в исходный файл (X.c). Затем другие файлы могут # включить "X.h"
и вызвать функцию.
Это не обязательно, но не использовать прототипы - плохая практика.
С помощью прототипов компилятор может проверить, правильно ли вы вызываете функцию (используя правильное количество и тип параметров).
Без прототипов возможно следующее:
// 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 позволяет вызывать функции, даже если они не были ранее объявлены, но я настоятельно рекомендую вы должны объявить прототип для всех функций перед их использованием, чтобы компилятор мог спасти вас, если вы используете неправильные аргументы.
Никогда не требуется объявлять прототип для функции в 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.
Тем не менее, всегда рекомендуется объявлять прототип функции перед ее вызовом.
Дополнительное примечание: Выше я сказал, что никогда не требуется объявлять прототип функции. Фактически, для некоторых функций это требование. Чтобы правильно вызвать вариационную функцию в C (например, printf
), функция должна быть объявлена с прототипом перед точкой вызова. В противном случае поведение не определено. Это относится как к C89 / 90, так и к C99.
это не обязательно, если функция определена до ее использования.
Прототип функции не является обязательным в соответствии со стандартом C99
.
Не обязательно объявлять функцию для компиляции вызывающего кода. Однако есть предостережения. Предполагается, что необъявленная функция возвращает int
, и компилятор сначала выдаст предупреждения о том, что функция не объявлена, а затем о любых несоответствиях в типе возвращаемого значения и типах параметров.
При этом очевидно, что правильное объявление функций с помощью прототипов - гораздо лучшая практика.