Альтернативный синтаксис (K & R) C для объявления функции по сравнению с прототипами
Вопрос
Что в этом полезного C
синтаксис — использование объявлений функций в стиле 'K & R'?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Я смог написать это в Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
Я не понимаю.В чем смысл этого синтаксиса?Я могу писать:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
Единственное, что, по-видимому, указывается, - это количество используемых параметров и возвращаемый тип.Я думаю, параметры без типов - это вроде как круто, но зачем разрешать это и int paranName
после объявления функции?Это странно.
Кроме того, это все еще стандартный C?
Решение
Вопрос, который вы задаете, на самом деле состоит из двух вопросов, а не из одного.Большинство ответов до сих пор пытались охватить все это общим ответом "это стиль K & R", в то время как на самом деле лишь небольшая его часть имеет какое-либо отношение к тому, что известно как стиль K & R (если вы так или иначе не рассматриваете весь язык C как "K & R-style" :)
Первая часть - это странный синтаксис, используемый в функции определение
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
На самом деле это определение функции в стиле K & R.Другой ответ довольно хорошо описал это.И на самом деле в этом нет ничего особенного.Синтаксис устарел, но по-прежнему полностью поддерживается даже в C99 (за исключением правила "no implicit int" в C99, означающего, что в C99 вы не можете опустить объявление p2
).
Вторая часть имеет мало общего с K & R-стилем.Я имею в виду тот факт, что функция может быть вызвана с "замененными местами" аргументами, т.е.при таком вызове проверка типа параметра не выполняется.Это имеет очень мало общего с определением в стиле K & R как таковым, но это имеет прямое отношение к вашей функции, не имеющей прототипа.Видите ли, в C, когда вы объявляете функцию, подобную этой
int foo();
на самом деле он объявляет функцию foo
для этого требуется неопределенное количество параметров неизвестного типа.Вы можете назвать это следующим образом
foo(2, 3);
и как
j = foo(p, -3, "hello world");
и так далее (вы поняли идею);
Только вызов с правильными аргументами будет "работать" (это означает, что остальные приводят к неопределенному поведению), но обеспечить его корректность полностью зависит от вас.Компилятору не требуется диагностировать неправильные параметры, даже если он каким-то волшебным образом знает правильные типы параметров и их общее количество.
На самом деле, такое поведение является особенность языка Си.Опасная, но, тем не менее, особенность.Это позволяет вам делать что-то вроде этого
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
т. е.смешайте различные типы функций в "полиморфном" массиве без каких-либо приведений типов (однако переменные типы функций здесь использоваться не могут).Опять же, неотъемлемые опасности этого метода совершенно очевидны (я не помню, чтобы когда-либо использовал его, но могу представить, где он может быть полезен), но это, в конце концов, C.
Наконец, бит, который связывает вторую часть ответа с первой.Когда вы создаете определение функции в стиле K & R, оно не вводит прототип для функции.Что касается типа функции, то ваш func
определение объявляет func
как
int func();
т. е.ни типы, ни общее количество параметров не объявлены.В своем первоначальном посте вы говорите "...кажется, это указывает на то, сколько параметров он использует ...".Формально говоря, это не так!После вашего двухпараметрического K & R-стиля func
определение, которое вы все еще можете назвать func
как
func(1, 2, 3, 4, "Hi!");
и в этом не будет никакого нарушения ограничений.(Обычно качественный компилятор выдает вам предупреждение).
Кроме того, иногда упускается из виду тот факт, что
int f()
{
return 0;
}
это также определение функции в стиле K & R, которое не вводит прототип.Чтобы сделать его "современным", вам нужно было бы поставить явный void
в списке параметров
int f(void)
{
return 0;
}
Наконец, вопреки распространенному мнению, как определения функций в стиле K & R, так и объявления непрототипированных функций полностью поддерживаются в C99.Первый устарел с C89 / 90, если я правильно помню.C99 требует, чтобы функция была объявлена перед первым использованием, но объявление не обязательно должно быть прототипом.Путаница, по-видимому, проистекает из популярной терминологической путаницы:многие люди называют объявление любой функции "прототипом", в то время как на самом деле "объявление функции" - это не то же самое, что "прототип".
Другие советы
Это довольно старый синтаксис K & R C (предшествующий ANSI / ISO C).В настоящее время вам больше не следует им пользоваться (так как вы уже заметили его главный недостаток:компилятор не будет проверять типы аргументов за вас).Тип аргумента на самом деле по умолчанию равен int
в вашем примере.
В то время, когда использовался этот синтаксис, иногда можно было встретить такие функции, как
foo(p, q)
{
return q + p;
}
что на самом деле было допустимым определением, поскольку типы для foo
, p
, и q
значение по умолчанию равно int
.
Это просто старый синтаксис, который предшествует синтаксису "ANSI C", с которым вы, возможно, более знакомы.Это называется "K &R C", как правило.
Компиляторы поддерживают его, чтобы он был полным и, конечно, мог обрабатывать старые базы кода.
Это оригинальный синтаксис K & R до того, как C был стандартизирован в 1989 году.C89 представил прототипы функций, заимствованные из C ++, и устарел синтаксис K & R.Нет никаких причин использовать его (и множество причин не делать этого) в новом коде.
Это пережиток тех времен, когда в C не было прототипов функций.Давным-давно (я думаю) предполагалось, что функции будут возвращать int
и предполагалось , что все его аргументы будут int
.Проверка параметров функции не производилась.
Вам гораздо лучше использовать прототипы функций на текущем языке C.
А ты должен используйте их в C99 (C89 по-прежнему принимает старый синтаксис).
А C99 требует, чтобы функции были объявлены (возможно, без прототипа).Если вы пишете новую функцию с нуля, вам необходимо предоставить объявление ...сделайте это тоже прототипом:вы ничего не теряете и получаете дополнительную проверку от компилятора.