Почему функция без параметров (по сравнению с фактическим определением функции) составить?
Я только что наткнулся на чей-то код C, который я запутался, почему он компилируется. Есть два момента, которые я не понимаю.
во-первых, прототип функции не имеет параметров по сравнению с фактическим определением функции. Во-вторых, параметр в определении функции не имеет типа.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
почему это работает? Я протестировал его в нескольких компиляторах, и он отлично работает.
11 ответов:
все остальные ответы верны, но только для завершение
функция объявляется следующим образом:
return-type function-name(parameter-list,...) { body... }
return-type - тип переменной, которую возвращает функция. Это не может быть тип массива или тип функции. если не дано, то int предполагается.
function-name - это имя функции.
parameter-list список параметров, которые функция принимает разделенные запятыми. если параметры не заданы, то функция не принимает никаких и должен быть определен с пустым набором скобки или с ключевым словом void. Если впереди нет типа переменной переменной в списке параметров, то инт предполагается. Массивы и функции не передаются в функции, а преобразуются автоматически к указателям. Если список заканчивается многоточием (,...), затем нет заданного количества параметров. Примечание: заголовок stdarg.ч может быть используется для доступа к аргументам при использовании многоточия.
и снова для полноты картины. из спецификации C11 6: 11: 6 (страницы: 179)
на использование деклараторов функций с пустыми скобками (не Prototype-format тип параметра деклараторы)является устаревшим особенность.
В C
func()
означает, что вы можете передать любое количество аргументов. Если вы не хотите никаких аргументов, то вы должны признатьfunc(void)
. Тип, который вы передаете в свою функцию, если не указано значение по умолчаниюint
.
int func();
является устаревшим объявлением функции со времен, когда не было стандарта C, т. е. дней K&R C (до 1989 года, когда был опубликован первый стандарт "ANSI C").помните, что было нет прототипов в K&R C и ключевое слово
void
еще не изобрели. Все, что вы могли сделать, это рассказать компилятору о тип возвращаемого функции. Пустой список параметров в K&R C означает " неопределенный, но исправлено " количество аргументов. Fixed означает, что вы должны вызвать функцию с то же самое количество аргументов каждый раз (в отличие от variadic какprintf
, где число и тип могут варьироваться для каждого вызова).многие компиляторы будут диагностировать эту конструкцию; в частности
gcc -Wstrict-prototypes
скажет вам ,что "объявление функции не является прототипом", который находится на месте, потому что он выглядит как прототип (особенно, если вы отравились C++!), но не. Это старый типа K&R с декларации типа.правило: никогда не оставляйте пустым объявление списка параметров, используйте
int func(void)
чтобы быть точным. Это превращает объявление типа возврата K&R в правильный прототип C89. Компиляторы счастливы, разработчики счастливы, статические шашки счастливы. Однако те, кто вводит в заблуждение^W^Wfond C++, могут съежиться, потому что им нужно вводить дополнительные символы, когда они пытаются использовать свои навыки иностранного языка : -)
- пустой список параметров означает "любые аргументы", поэтому определение не является неправильным.
- предполагается, что отсутствующий тип
int
.Я бы рассмотрел любую сборку, которая передает это, чтобы не хватало настроенного уровня предупреждения / ошибки, хотя нет смысла в том, чтобы это позволяло фактический код.
Это K&R объявление и определение функции стиля. От стандарта C99 (ISO / IEC 9899: TC3)
раздел 6.7.5.3 Деклараторы функций (включая прототипы)
в списке идентификаторов объявляются только идентификаторы параметров функции. Пустота список в деклараторе функций, который является частью определения этой функции, указывает, что функция не имеет параметров. пустой список в Декларатор функции не часть определение этой функции указывает, что нет информации о количестве или типах параметров входит в комплект поставки. (Если оба типа функций являются "старыми", типы параметров не сравниваются.)
раздел 6.11.6 деклараторы функций
6.11.7 определения функциииспользование деклараторов функций с пустыми скобками (не параметр prototype-format деклараторы типа) - это отживающие функции.
использование определений функций с отдельными идентификаторами параметров и списками объявлений (не прототип-формат тип параметра и идентификатор деклараторы) является отживающие функции.
что означает старый стиль K&R стиль
пример:
объявления:
int old_style();
определение:
int old_style(a, b) int a; int b; { /* something to do */ }
C предполагает
int
если в списке возвращаемых функций и параметров не указан тип. Только для этого правила возможны следующие странные вещи.определение функции выглядит следующим образом.
int func(int param) { /* body */}
если его прототип вы пишите
int func(int param);
в прототипе можно указать только тип параметров. Имя параметров не является обязательным. Так что
int func(int);
также, если вы не указываете тип параметра, но имя
int
предполагается как тип.int func(param);
если вы идете дальше, следующие работы тоже.
func();
компилятор предполагает
int func()
когда вы пишитеfunc()
. Но не ставьтеfunc()
внутри тела функции. Это будет вызов функции
в Старом-C как в ANSI-C "нетипизированный формальный параметр", взять dimencion вашей работы, регистрации или эксплуатации возможность глубины (теневые регистры или инструкция накопительного цикла), в 8-битные ЦПУ, будет типа INT16, в 16-разрядных микропроцессоров, а так будет типа INT16 и т. д., В случае 64бит архитектуры могут выбрать для компиляции такие параметры, как:- m32.
хотя это кажется более простой реализацией на высоком уровне, Для передачи нескольких параметров работа программиста на этапе управления типом данных dimencion становится более требовательной.
в других случаях, для некоторых архитектур микропроцессоров, компиляторы ANSI настроены, использовали некоторые из этих старых функций для оптимизации использования кода, заставляя расположение этих " нетипизированных формальных параметры " для работы внутри или вне рабочего регистра, сегодня вы получаете почти то же самое с использованием "volatile" и "register".
но следует отметить, что большинство современных компиляторов, не делайте никакого различия между двумя типами объявления параметров.
примеры компиляции с gcc под linux:
в любом случае заявление прототип локально бесполезен, потому что нет вызова без параметров ссылка на этот прототип будет упущена. Если вы используете систему с "нетипизированным формальным параметром" для внешнего вызова, перейдите к созданию декларативного прототипа типа данных.такой:
int myfunc(int param);
что касается типа параметра, здесь уже есть правильные ответы, но если вы хотите услышать это от компилятора, вы можете попробовать добавить некоторые флаги (флаги почти всегда хорошая идея в любом случае).
компиляция программы с помощью
gcc foo.c -Wextra
Я:foo.c: In function ‘func’: foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
странно
-Wextra
не ловит это дляclang
(он не распознает-Wmissing-parameter-type
почему-то, может быть, для исторических, упомянутых выше) но-pedantic
тут:foo.c:5:10: warning: parameter 'param' was not declared, defaulting to type 'int' [-pedantic] int func(param) ^ 1 warning generated.
и для прототипа вопрос, как было сказано выше
int func()
относится к произвольным параметрам, если вы не определяете его какint func(void)
который затем даст вам ошибки, как ожидалось:foo.c: In function ‘func’: foo.c:6:1: error: number of arguments doesn’t match prototype foo.c:3:5: error: prototype declaration foo.c: In function ‘main’: foo.c:12:5: error: too many arguments to function ‘func’ foo.c:5:5: note: declared here
или
clang
как:foo.c:5:5: error: conflicting types for 'func' int func(param) ^ foo.c:3:5: note: previous declaration is here int func(void); ^ foo.c:12:20: error: too many arguments to function call, expected 0, have 1 int bla = func(10); ~~~~ ^~ foo.c:3:1: note: 'func' declared here int func(void); ^ 2 errors generated.
если объявление функции не имеет параметров, т. е. пусто, то оно принимает неопределенное количество аргументов. Если вы хотите, чтобы он не принимал никаких аргументов, измените его на:
int func(void);
вот почему я обычно советую людям компилировать свой код с помощью:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
эти флаги обеспечивают несколько вещей:
- -Wmissing-variable-declarations: невозможно объявить нестатическую функцию, не получив сначала прототип. Это делает более вероятным, что прототип в заголовочном файле соответствует фактическому определению. Кроме того, он принудительно добавляет ключевое слово static к функциям, которые не должны быть видны публично.
- -wstrict-variable-declarations: прототип должен правильно перечислить аргументы.
- -Wold-style-definition: само определение функции также должно правильно перечислять аргументы.
эти флаги также используется по умолчанию во многих проектах с открытым исходным кодом. Например, во FreeBSD эти флаги включены при сборке с WARNS=6 в вашем файле Makefile.
сэр, в C++ (и только C++) вы можете определить несколько функций с одинаковым именем с разными параметрами. Например:
int func(); int func(int test); int func(char testing123);
следует подготовить. Чтобы выбрать, какую функцию использовать, просто передайте этот тип переменной в скобки при компиляции.
например:
int testing123=2; func(testing123);
вызовет func (int test).
, тогда как
char test='a'; func(test);
вызовет func (char).
вам не нужно имена переменных в заголовке функции, хотя до тех пор, пока прототип функции (вы знаете, строка вверху, которая имеет только функцию без кода в ней) соответствует именам в фактической функции ниже, вы будете в порядке (например, вместо
int func(int)
вы могли бы также иметь intfunc(int avariable).
Что касается переменной в прототипе компиляции без типа, то она, вероятно, по умолчанию имеет тип, скорее всего, int (хотя я не уверен, что тип по умолчанию зависит от компилятора или нет.)