Синтаксис функции C, типы параметров, объявленные после списка параметров

Я относительно не знаком с C. Я столкнулся с формой функционального синтаксиса, который я никогда раньше не видел, где типы параметров определяются после этого списка параметров. Может ли кто-нибудь объяснить мне, как он отличается от типичного синтаксиса функции C?

Пример:

int main (argc, argv) int argc; char *argv[]; { return(0); } 

Это синтаксис старого стиля для списков параметров, который по-прежнему поддерживается. В K & R C вы также можете оставить объявления типа, и они будут по умолчанию для int. т.е.

 main(argc, argv) char *argv[]; { return 0; } 

будет той же самой функцией.

Интересно также различие между вызовами и функциями без прототипа. Рассмотрим старое определение стиля:

 void f(a) float a; { /* ... */ } 

В этом случае вызывающим соглашением является то, что все аргументы продвигаются перед передачей функции. Поэтому, если f получает double но параметр имеет тип float (что совершенно верно), компилятор должен испускать код, который преобразует double в float до выполнения тела функции.

Если вы включите прототип, компилятор больше не делает таких автоматических рекламных акций, и любые переданные данные преобразуются в типы параметров прототипа, как если бы они были назначены. Таким образом, следующее не является законным и приводит к неопределенному поведению:

 void f(float a); void f(a) float a; { } 

В этом случае определение функции преобразует представленный параметр из double (продвигаемой формы) в float потому что определение является старым. Но параметр был представлен как float, потому что функция имеет прототип. Ваши варианты решения противоречий следующие:

 // option 1 void f(double a); void f(a) float a; { } // option 2 // this declaration can be put in a header, but is redundant in this case, // since the definition exposes a prototype already if both appear in a // translation unit prior to the call. void f(float a); void f(float a) { } 

Вариант 2 должен быть предпочтительнее, если у вас есть выбор, потому что он избавляется от определения старого стиля спереди. Если такие противоречивые типы функций для функции отображаются в одной и той же единицы перевода, компилятор обычно скажет вам (но не обязательно). Если такие противоречия появятся над несколькими единицами перевода, ошибка, возможно, останется незамеченной и может привести к затруднению outlookирования ошибок. Лучше избегать этих старых определений стиля.

Это так называемый код K & R или декларация старого стиля .

Обратите внимание, что эта декларация существенно отличается от современной декларации. Объявление K & R не вводит прототип функции, а это означает, что он не предоставляет типы параметров внешнему коду.

Хотя старый синтаксис определения функции по-прежнему работает (с предупреждениями, если вы спросите своего компилятора), использование их не предоставляет прототипов функций.
Без прототипов функций компилятор не будет проверять правильность вызова функций.

 #include  int foo(c) int c; { return printf("%d\n", c); } int bar(x) double x; { return printf("%f\n", x); } int main(void) { foo(42); /* ok */ bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */ return 0; } 

Когда программа запускается, вывод на моей машине

 $ gcc proto.c $ gcc -Wstrict-prototypes proto.c proto.c:4: warning: function declaration isn't a prototype proto.c:10: warning: function declaration isn't a prototype $ ./a.out 42 0.000000 

Нет никакой разницы, просто это старый синтаксис для объявлений функций в C – он использовался до ANSI. Никогда не пишите такой код, если вы не планируете передавать его своим друзьям с 80-х годов . Кроме того, никогда не зависеть от неявных допущений типа (как представляется, другой ответ)

Его просто такая же, но старая мода. Вероятно, вы обнаружили, что это старый, устаревший код.

  • Имя таблицы как параметр функции PostgreSQL
  • «Правильный» способ указать необязательные аргументы в R-функциях
  • Заполните непересекающиеся пустые ячейки со значением из ячейки над первым пробелом
  • Макро против функции в C
  • Почему C-массив имеет неправильное значение sizeof (), когда он передается функции?
  • Как округлить до ближайшего 0,5?
  • Использование boost-streamа и нестатической функции classа
  • Как сделать .lib-файл, когда есть .dll-файл и заголовочный файл
  • Как построить несколько функций на одной фигуре в Matplotlib?
  • Почему нам нужно использовать `int main`, а не` void main` в C ++?
  • Вызов библиотеки C ++ в C #
  • Interesting Posts

    Разрешения для файлов в Windows XP

    В чем разница между ошибками и исключениями?

    Шрифт гиперссылки в Excel всегда изменяется на шрифт / размер шрифта по умолчанию

    Регулярное выражение для строки, которая не начинается с последовательности

    Беспроводная сеть медленнее, чем ожидалось

    Папка «Мои документы» для нового местоположения в Windows 7

    Выбор наилучшего первичного ключа + система нумерации

    VideoView, чтобы соответствовать высоте родителя и сохранить соотношение сторон

    Scp между двумя удаленными хостами от моего (третьего) компьютера

    Как я могу запустить (16-разрядный) .COM исполняемый файл, который был переименован в .COS?

    Программное обеспечение для измерения рабочего времени на рабочем столе

    Вставить библиотеку Zxing без использования приложения сканера штрих-кода

    Патч Windows 10-UxStyle работает неправильно

    MongoDB Query Help – запрос значений любого ключа в под-объекте

    Как установить расширенные ассоциации файлов в Windows 7?

    Давайте будем гением компьютера.