Объявление функции: K & R vs ANSI

Каковы различия между объявлением функции K & R и объявлением функции ANSI?

Ответ 1

Синтаксис K & R устарел, вы можете пропустить его, если вам не нужно поддерживать очень старый код.

// K&R syntax
int foo(a, p) 
    int a; 
    char *p; 
{ 
    return 0; 
}

// ANSI syntax
int foo(int a, char *p) 
{ 
    return 0; 
}

Ответ 2

Устаревшие объявления K & R-стиля/определения

Когда Керниган и Ритчи впервые опубликовали "Язык программирования C", C еще не предлагал полнофункциональные прототипы. Передовые декларации функций существуют, но с единственной целью указывать тип возврата. Для функций, возвращаемых int, они не требовались до C99.

В соответствии с C89 было добавлено понятие прототипа функции, которое также указывает типы параметров (и, неявно, их число). Поскольку прототип также является объявлением функции, неофициальный термин "объявление функции K & R" иногда используется для объявления функции, которое также не является прототипом.

// K&R declarations, we don't know whether these functions have parameters.
int foo(); // this declaration not strictly necessary until C99, because it returns int
float bar();

// Full prototypes, specifying the number and types of parameters
int foo(int);
float bar(int, float);

// K&R definition of a function
int foo(a)
    int a; // parameter types were declared separately
{
    // ...
    return 0;
}

// Modern definition of a function
float bar(int a, float b) 
{
    // ...
    return 0.0;
}

Декларация о случайности K & R

Стоит отметить, что новички на C могут случайно использовать объявления K & R, когда они намереваются использовать полный прототип, потому что они могут не понимать, что пустой список параметров должен быть указан как void.

Если вы объявляете и определяете функцию как

// Accidental K&R declaration
int baz(); // May be called with any possible set of parameters

// Definition
int baz() // No actual parameters means undefined behavior if called with parameters.
          // Missing "void" in the parameter list of a definition is undesirable but not
          // strictly an error, no parameters in a definition does mean no parameters;
          // still, it better to be in the habit of consistently using "void" for empty
          // parameter lists in C, so we don't forget when writing prototypes.
{
    // ...
    return 0;
}

... тогда вы фактически не дали прототип функции, которая не принимает никаких параметров, а объявляет в K & R-style для функции, которая принимает неизвестное количество параметров неизвестного типа.

AnT отмечает в этот ответ к аналогичному вопросу о том, что этот синтаксис устарел, но по-прежнему является законным с C99 (и эта функция указывает на функции с неизвестным числом и тип параметров по-прежнему имеет потенциальные приложения, хотя и с высоким риском поведения undefined); как таковые, совместимые компиляторы будут, в лучшем случае, вызывать предупреждение, если функция объявлена ​​или вызвана без надлежащего прототипа.

Функции вызова без прототипов менее безопасны, поскольку компилятор не может проверить, что вы правильно указали количество и типы параметров в правильном порядке; undefined поведение, если вызов на самом деле не правильный.

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

// Modern declaration of a parameterless function.
int qux(void);  // "void" as a parameter type means there are no parameters.
                // Without using "void", this would be a K&R declaration.

// Modern definition of a parameterless function
int qux(void)
{
    // ...
    return 0;
}

Ответ 3

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

Рассмотрим современную нотацию C11 простой программы HelloWorld:

int main(int argc, char **argv) {
    printf("hello world\n");
    return 0;
}

Это эквивалентно стилю нотации K и R:

main(argc, argv)
int argc;
char **argv;
{
 printf("hello world\n");
 return 0;
}

Обратите внимание, что int до main() игнорируется, но код все еще компилируется. Это часть определения K и R.

Цитата Википедия:

В ранних версиях C только функции, которые возвращали значение non-int, которое необходимо было объявить, если оно используется до определения функции; предполагается, что функция, используемая без какого-либо предыдущего объявления, возвращает тип int, если его значение было использовано.

- источник: https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C

Это, возможно, устаревший стиль кодирования, и его следует избегать из-за проблем с ясностью, но довольно часто старые алгоритмы алгоритма поддерживают этот тип стиля K и R.