Объявление функции: K&R против ANSI
Каковы различия между объявлением функции K&R и объявлением функции ANSI?
3 ответа
Синтаксис 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;
}
Устаревшие объявления и определения в стиле 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's 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 для функции, которая принимает неизвестное число параметров неизвестного типа.
AnT отмечает в этом ответе на аналогичный вопрос, что этот синтаксис устарел, но все еще допустим с C99 (и что указатели на функции с неизвестным числом и типом параметров по-прежнему имеют потенциальное применение, хотя и с высоким риском неопределенного поведения); таким образом, совместимые компиляторы в лучшем случае будут выдавать предупреждение, если функция объявлена или вызвана без надлежащего прототипа.
Вызов функций без прототипов менее безопасен, потому что компилятор не может проверить, что вы передали правильное число и типы параметров в правильном порядке; неопределенное поведение приводит к тому, что вызов на самом деле не правильный.
Правильный способ объявить и определить функцию без параметров, конечно:
// 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;
}
Я просто хочу добавить, что в традиционных модификаторах типа стиля 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 только функции, которые возвращали не-int значение, должны были быть объявлены, если они использовались до определения функции; предполагается, что функция, используемая без какого-либо предыдущего объявления, возвращает тип int, если используется ее значение.
--источник: https://en.wikipedia.org/wiki/C_(programming_language)
Возможно, это унаследованный стиль кодирования, и его следует избегать из-за проблем с ясностью, но довольно часто старые учебники по алгоритму предпочитают этот вид стиля K & R.