C: Функция, определенная без типов аргументов [duplicate]

Разница между Thread и runnable. Если мы создаем Thread с использованием класса Thread, тогда количество потоков равно количеству созданного нами объекта. Если мы создаем поток, реализуя интерфейс runnable, мы можем использовать один объект для создания нескольких потоков. Один объект разделяется несколькими Thread.So он будет потреблять меньше памяти

. Поэтому в зависимости от требования, если наш данные не являются сенситивными. Таким образом, он может быть разделен между несколькими Thread, которые мы можем использовать интерфейс Runnable.

60
задан Jonathan Leffler 10 August 2016 в 13:59
поделиться

6 ответов

Вопрос, который вы задаете, - это действительно два вопроса, а не один. Большинство ответов до сих пор пытались охватить всю вещь с помощью общего одеяла «это ответ K & amp; R style», в то время как на самом деле лишь малая его часть имеет какое-либо отношение к тому, что известно как стиль K & amp; R (если вы не видите весь язык C как «K & amp; R-стиль» так или иначе:)

Первая часть - странный синтаксис, используемый в определении функции

int func(p, p2)
void *p;
int  p2; /* <- optional in C89/90, but not in C99 */
{
  return 0;
}

Это фактически определение функции K & amp; R-стиля. Другой ответ на это довольно хорошо. И на самом деле этого мало. Синтаксис устарел, но полностью поддерживается даже в C99 (за исключением правила «no implicit int» в C99, что означает, что на C99 вы не можете опустить объявление p2).

Второй часть имеет мало общего с K & amp; R-style. Я обращаюсь к тому факту, что функция может вызываться с «замененными» аргументами, т. Е. В таком вызове не происходит проверки типа параметра. Это очень мало связано с определением K & amp; R-style per se, но оно имеет все, что связано с тем, что ваша функция не имеет прототипа. Вы видите, что в C, когда вы объявляете такую ​​функцию

int foo();

, она фактически объявляет функцию foo, которая принимает неуказанное количество параметров неизвестного типа . Вы можете назвать его как

foo(2, 3);

и как

j = foo(p, -3, "hello world");

ans и так далее (вы получаете идею);

Только вызов с правильными аргументами будет «работать» (что означает, что другие производят неопределенное поведение), но это полностью зависит от вас, чтобы обеспечить его правильность. Компилятор не обязан диагностировать неправильные, даже если он каким-то образом знает правильные типы параметров и их общее число.

На самом деле это поведение является языка C. Однако опасный, но особенный. Это позволяет вам сделать что-то подобное

void foo(int i);
void bar(char *a, double b);
void baz(void);

int main()
{
  void (*fn[])() = { foo, bar, baz };
  fn[0](5);
  fn[1]("abc", 1.0);
  fn[2]();
}

i.e. смешивать разные типы функций в «полиморфном» массиве без каких-либо типов (типы вариационной функции здесь не могут быть использованы). Опять же, присущие опасности этой техники совершенно очевидны (я не помню, чтобы когда-либо ее использовали, но я могу представить, где это может быть полезно), но это C в конце концов.

Наконец, бит, который связывает вторая часть ответа на первый. Когда вы выполняете определение функции K & amp; R-стиля, оно не вводит прототип функции. Что касается типа функции, ваше определение func объявляет func как

int func();

i.e. ни типы, ни общее количество параметров не объявлены. В своем оригинальном посте вы говорите: «... кажется, это то, сколько параметров он использует ...». Формально это не так! После вашего двухпараметрического определения K & amp; R-style func вы все еще можете вызвать func как

func(1, 2, 3, 4, "Hi!");

, и в нем не будет никаких ограничений. (Как правило, качественный компилятор даст вам предупреждение).

Кроме того, иногда упускается из виду факт, что

int f()
{
  return 0;
}

также является определением функции K & amp; R-стиля, которое не вводит прототип. Чтобы сделать его «современным», вам нужно будет поместить явный void в список параметров

int f(void)
{
  return 0;
}

. Наконец, вопреки распространенному мнению, как определения функций K & amp; R-стиля, Прототипные объявления функций полностью поддерживаются в C99. Первый был устаревшим с C89 / 90, если я правильно помню. C99 требует, чтобы функция была объявлена ​​до первого использования, но декларация не требуется для прототипа. Путаница, по-видимому, проистекает из популярного терминологического смешения: многие люди называют любое объявление функции «прототипом», а на самом деле «объявление функции» - это не то же самое, что «прототип».

131
ответ дан parttimeturtle 20 August 2018 в 11:41
поделиться
  • 1
    очень приятно объяснил, особенно. «функция без прототипа» часть. – N 1.1 26 February 2010 в 09:11
  • 2
    Но какова разница между функцией varargs и непрототируемой. – Sebastian 26 September 2013 в 10:09
  • 3
    @Sebastian Godelet varargs unnececairly строго. Например, вызов функции vararg с одним int и выведение его в виде байтов является недопустимым. Таким образом, определяется функция только с параметрами vararg. – YoYoYonnY 4 June 2016 в 21:57

Это более старый стиль деклараций функций. См. Эту ссылку.

https://stackoverflow.com/questions/22500/what-are-the-major-differences-between-ansi-c-and-kr-c текст ссылки

0
ответ дан Community 20 August 2018 в 11:41
поделиться
  • 1
    Привет, Леонидас, не могли бы вы добавить более подробную информацию к этому ответу или (теперь, когда у вас есть репутация), превратив это в комментарий? – jrh 9 February 2017 в 18:50

Это довольно старый синтаксис K & amp; R C (предварительные даты ANSI / ISO C). В настоящее время вы больше не должны его использовать (поскольку вы уже заметили его главный недостаток: компилятор не будет проверять типы аргументов для вас). Тип аргумента по умолчанию по умолчанию соответствует int в вашем примере.

В то время этот синтаксис использовался, иногда можно было найти такие функции, как

foo(p, q) 
{
    return q + p;
}

, который фактически был действительным как типы для foo, p и q по умолчанию int.

17
ответ дан Dirk 20 August 2018 в 11:41
поделиться

Это реликвия, когда у C не было прототипов для функций. Тогда, как мне кажется, предполагается, что функции возвращаются int, и все его аргументы считались int.

Вам не удалось выполнить проверку параметров функции на текущем языке C. И вы должны использовать их в C99 (C89 по-прежнему принимает старый синтаксис).

И C99 требует, чтобы функции были объявлены (возможно, без прототипа). Если вы пишете новую функцию с нуля, вам нужно предоставить декларацию ... сделать ее прототипом: вы ничего не теряете и получаете дополнительную проверку от компилятора.

1
ответ дан pmg 20 August 2018 в 11:41
поделиться
  • 1
    Неправильно. В C99 функции должны быть явно объявлены до их вызова. Тем не менее, C99 не запрашивает проротированную декларацию. C99 полностью поддерживает синтаксис K & amp; R с одним изменением: неявное правило int было удалено. – AnT 27 October 2009 в 14:50
  • 2
    Вы правы, спасибо. Отредактировал мой ответ. – pmg 27 October 2009 в 15:22

Это оригинальный синтаксис K & amp; R до того, как C был стандартизован в 1989 году. C89 представила прототипы функций, заимствованные из C ++, и устарела синтаксис K & amp; R. Нет причин использовать его (и множество причин не) в новом коде.

1
ответ дан Robert Gamble 20 August 2018 в 11:41
поделиться

Это просто старый синтаксис, который предваряет синтаксис «ANSI C», с которым вы, возможно, более знакомы. Обычно это называется « K & amp; R C ».

Компиляторы поддерживают его, чтобы быть полным, и, конечно, иметь возможность обрабатывать старые базы кода.

4
ответ дан unwind 20 August 2018 в 11:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: