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

Этот вопрос уже имеет ответ здесь:

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

54
задан Mohit Deshpande 4 April 2010 в 05:59
поделиться

8 ответов

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

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

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

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

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

63
ответ дан 7 November 2019 в 07:46
поделиться

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

1
ответ дан 7 November 2019 в 07:46
поделиться

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

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

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

// 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);
}
4
ответ дан 7 November 2019 в 07:46
поделиться

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

1
ответ дан 7 November 2019 в 07:46
поделиться

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

65
ответ дан 7 November 2019 в 07:46
поделиться

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

6
ответ дан 7 November 2019 в 07:46
поделиться

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

1
ответ дан 7 November 2019 в 07:46
поделиться

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

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

0
ответ дан 7 November 2019 в 07:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: