В чем разница между объявлением функции K & и объявлением функции ANSI?Объявление функции: K & R vs ANSI
ответ
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 Заявления/Определения &-Style 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 отмечает в this answer аналогичный вопрос о том, что этот синтаксис является устаревшим, но все еще законным с 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;
}
Вам нужно уточнить, что вы подразумеваете под «более старыми версиями C». Вы говорите: _Дополнительные версии языка C не требуют полнофункциональных прототипов, но все еще требуют прямого объявления функции до того, как ее можно было бы назвать. Но более старые версии C, означающие pre-standard C, не имели прототипов вообще и не требовал прямого объявления функции до ее вызова. Даже C89/C90 не требовали таких передовых деклараций. Это C99 требовало объявления функций (но все же не обязательных прототипов) перед использованием. –
@JonathanLeffler Спасибо за советы, я прочитал немного больше (в основном статью Википедии о эпохе K & R C) и очистил его, я думаю, что он должен быть исторически точным сейчас. –
Я просто хочу добавить, что в традиционном K & модификаторов типа R типа для функций, возвращающих int
значения Арена» t даже необходимо.
Рассмотрим современные С11 обозначения простой программы 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, если его значение было использовано.
--source: https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
Это, возможно, является наследием кодирования стиля и его следует избегать из-за проблем ясности, но довольно часто старые алгоритм учебники пользу такого рода K & стиле R.
И для мазохиста вы можете иметь «main (argc, argv) char ** argv; {...} ', поскольку тип аргументов без явной спецификации типа был, по умозаключению,' int'. Кроме того, 'function (a, b, c, d) char * d, double c, a; {...} 'тоже было хорошо; имена не должны быть указаны в разделе типа в том порядке, в котором они отображаются в списке аргументов. –
Можете ли вы привести пример каждого стиля? –
Связанный с этим вопрос: http://stackoverflow.com/questions/1630631/what-is-useful-about-this-c-syntax – sharptooth
Это «K & R», а не «knr» (я исправил вопрос для вас) , что означает Керниган и Ричи и обычно относится к синтаксису С, описанному в их книжной книге на C около 1978 года, * Язык программирования C *. Эта статья может быть вам полезна: http://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C –