Почему функция без параметров (по сравнению с фактическим определением функции) составить?


Я только что наткнулся на чей-то код C, который я запутался, почему он компилируется. Есть два момента, которые я не понимаю.

во-первых, прототип функции не имеет параметров по сравнению с фактическим определением функции. Во-вторых, параметр в определении функции не имеет типа.

#include <stdio.h>

int func();

int func(param)
{
    return param;
}

int main()
{
    int bla = func(10);    
    printf("%d", bla);
}

почему это работает? Я протестировал его в нескольких компиляторах, и он отлично работает.

11 381

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 деклараторы функций

использование деклараторов функций с пустыми скобками (не параметр prototype-format деклараторы типа) - это отживающие функции.

6.11.7 определения функции

использование определений функций с отдельными идентификаторами параметров и списками объявлений (не прототип-формат тип параметра и идентификатор деклараторы) является отживающие функции.

что означает старый стиль 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:

main.c

main2.c

main3.c  
в любом случае заявление прототип локально бесполезен, потому что нет вызова без параметров ссылка на этот прототип будет упущена. Если вы используете систему с "нетипизированным формальным параметром" для внешнего вызова, перейдите к созданию декларативного прототипа типа данных.

такой:

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) вы могли бы также иметь int func(int avariable).

Что касается переменной в прототипе компиляции без типа, то она, вероятно, по умолчанию имеет тип, скорее всего, int (хотя я не уверен, что тип по умолчанию зависит от компилятора или нет.)