Проблема определения функции в стиле K&R

Работает следующий код:

int main()
{
   void foo(int);
   foo(3);
   return 0;
}
void foo(a) int a;
{
   printf("In foo\n");
}

а этот нет:

int main()
{
   void foo(float);
   foo(3.24);
   return 0;
}
void foo(a) float a;
{
   printf("In foo\n");
}

Почему это происходит?


person nitzs    schedule 29.01.2011    source источник
comment
Что вы имеете в виду под произведениями? Он компилируется или нет? Он запускается или нет? В чем проблема?   -  person Nick    schedule 29.01.2011
comment
Потому что 2-й пример не был допустимым синтаксисом дольше, чем кто-либо из нас был жив?   -  person Chris Becke    schedule 29.01.2011
comment
@Nick: Нет, это не компилируется. Это ошибка: конфликтующие типы для «foo».   -  person nitzs    schedule 29.01.2011


Ответы (1)


На самом деле, довольно интересный вопрос.

Это связано с эволюцией языка C и его обратной совместимостью со старыми разновидностями.

В обоих случаях у вас есть определение эпохи K&R для foo(), но объявление C99 (с прототипом) раньше.

Но в первом случае параметр int по умолчанию фактически является параметром, поэтому вызов функции совместим.

Во втором случае, однако, определение K&R вводит стандартное правило повышения аргумента из эпохи K&R, и тип параметра действительно double.

Но вы использовали современный прототип на месте вызова, сделав его float. Таким образом, код на месте вызова мог вытолкнуть настоящий float, который в любом случае отличается от double.

Если бы все ссылки на foo() были в стиле K&R, я полагаю, что максимум, что вы получили бы, было бы предупреждением, что компиляторы сделали бы тогда, и компилятор должен действовать таким образом, чтобы скомпилировать унаследованный код. Это был бы даже типобезопасный вызов, потому что все числа с плавающей запятой были бы повышены до двойных, по крайней мере, для интерфейса вызова процедуры. (Не обязательно для кода внутренней функции.)

person DigitalRoss    schedule 29.01.2011
comment
Строго говоря, я должен был сказать, что правила, включающие преобразование аргументов с плавающей запятой в двойные, называются продвижением аргументов по умолчанию. Кроме того, мы обычно называем любую версию ANSI C C99, потому что стандарт C99 заменил стандарт C89. Но поскольку мы конкретно обсуждали эволюцию языка, возможно, мне следовало отметить, что прототипы выражений возникли в C89. - person DigitalRoss; 29.01.2011
comment
Строго говоря, ANSI C устарел с 1990 года, поскольку ANSI C = C89. Первым стандартом ISO C является C90. Хотя, конечно, ANSI C и C90 идентичны по функциям и отличаются только нумерацией глав и различными другими косметическими средствами. - person Lundin; 29.01.2011
comment
Конечно, я пытался сослаться на версии с прототипами, которые начинались с ANSI C, но я думаю, что ISO C был бы лучшим выбором. - person DigitalRoss; 29.01.2011
comment
вопрос хороший но я никогда не напишу что-то подобное, всегда нужен прототип в шапке - person Mandrake; 31.01.2011