Синтаксис функции C, типы параметров, объявленные после списка параметров
Я относительно не знаком с C. Я столкнулся с формой функционального синтаксиса, который я никогда раньше не видел, где типы параметров определяются после этого списка параметров. Может ли кто-нибудь объяснить мне, как он отличается от типичного синтаксиса функции C?
Пример:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
Ответы
Ответ 1
Это синтаксис старого стиля для списков параметров, который по-прежнему поддерживается. В K & R C вы также можете оставить объявления типа, и они будут по умолчанию для int. то есть.
main(argc, argv)
char *argv[];
{
return 0;
}
будет той же самой функцией.
Ответ 2
То, что также интересно, это различие между вызовами функций и функциями без прототипа. Рассмотрим старое определение стиля:
void f(a)
float a; {
/* ... */
}
В этом случае вызывающее соглашение состоит в том, что все аргументы продвигаются перед передачей функции. Поэтому, если f
получает double
, но параметр имеет тип float
(что совершенно верно) компилятор должен испускать код, который преобразует double в float до выполнения тела функции.
Если вы включаете прототип, компилятор больше не делает таких автоматических рекламных акций, и любые переданные данные преобразуются в типы параметров прототипа, как если бы они были назначены. Итак, следующее не является законным и приводит к поведению undefined:
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 должен быть предпочтительнее, если у вас есть выбор, потому что он избавляется от определения старого стиля спереди. Если такие противоречивые типы функций для функции отображаются в одной и той же единицы перевода, компилятор обычно скажет вам (но не обязательно). Если такие противоречия появятся над несколькими единицами перевода, ошибка, возможно, останется незамеченной и может привести к затруднению прогнозирования ошибок. Лучше избегать этих старых определений стиля.
Ответ 3
Это так называемый код K & R или декларация старого стиля.
Обратите внимание, что это выражение существенно отличается от современной декларации. Объявление K & R не вводит прототип функции, а это означает, что он не предоставляет типы параметров внешнему коду.
Ответ 4
Пока старый синтаксис определения функции по-прежнему работает (с предупреждениями, если вы спросите своего компилятора), использование их не предоставляет прототипов функций.
Без прототипов функций компилятор не будет проверять правильность вызова функций.
#include <stdio.h>
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
Ответ 5
Нет никакой разницы, просто это старый синтаксис для объявлений функций в C - он использовался до ANSI. Никогда не пишите такой код, если вы не планируете передавать его своим друзьям из 80-х годов. Кроме того, никогда не зависит от неявных допущений типа (как кажется, кажется, другой ответ)
Ответ 6
Его просто такая же, но старая мода. Вероятно, вы обнаружили, что это старый, устаревший код.