Альтернативный синтаксис (K & R) C для объявления функции по сравнению с прототипами

StackOverflow https://stackoverflow.com/questions/1630631

Вопрос

Что в этом полезного 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 требует, чтобы функции были объявлены (возможно, без прототипа).Если вы пишете новую функцию с нуля, вам необходимо предоставить объявление ...сделайте это тоже прототипом:вы ничего не теряете и получаете дополнительную проверку от компилятора.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top