Есть ли разница между foo(void) и foo() в C++ или C?

Рассмотрим эти два определения функций:

void foo() { }

void foo(void) { }

Есть ли разница между этими двумя? Если нет, то почему там аргумент void? Эстетические причины?


person Landon    schedule 09.09.2008    source источник
comment
Для C Q/A здесь   -  person Antti Haapala    schedule 07.05.2018


Ответы (4)


В C:

  • void foo() означает "функция foo, принимающая неопределенное количество аргументов неопределенного типа"
  • void foo(void) означает "функция foo без аргументов"

В C++:

  • void foo() означает "функция foo без аргументов"
  • void foo(void) означает "функция foo без аргументов"

Таким образом, записывая foo(void), мы добиваемся одинаковой интерпретации на обоих языках и делаем наши заголовки многоязычными (хотя обычно нам нужно сделать с заголовками кое-что еще, чтобы сделать их действительно межъязыковыми; а именно, заключить их в extern "C", если мы' повторная компиляция С++).

person DrPizza    schedule 09.09.2008
comment
Но если бы C++ потребовал void, то можно было бы избежать самой неприятной проблемы синтаксического анализа. - person Adrian McCarthy; 04.01.2010
comment
Верно, но в C++ так много других дерьмовых синтаксических анализаторов, что нет никакого смысла ныть об одном из них. - person DrPizza; 04.01.2010
comment
На недавний вопрос @James Kanze опубликовал интересный лакомый кусочек. Сделайте репост здесь, чтобы не потерять его: первые версии C не позволяли указывать количество параметров, которые может принимать функция, поэтому void foo() был единственным синтаксисом для объявления функции. Когда были введены подписи, комитет C должен был устранить неоднозначность отсутствия параметра из старого синтаксиса и ввел синтаксис void foo(void). С++ взял его ради совместимости. - person Matthieu M.; 14.09.2011
comment
Можете ли вы привести пример C C90 и более поздних версий, где использование void foo() вместо void foo(void) приведет к функциональной разнице? т.е. Пользуюсь версией без пустоты уже много лет и проблем не заметил, я что-то упустил? - person chacham15; 07.11.2011
comment
Хорошо, теперь я понимаю разницу, но что я получу в C, если напишу void foo( void ) вместо void foo() ? Какова практическая причина писать void явно? - person unresolved_external; 01.02.2012
comment
Вы получите предупреждения, если не ошибки, если когда-либо по ошибке попытаетесь передать аргументы функции без аргументов. - person DrPizza; 02.02.2012
comment
Теперь я понимаю, почему void может быть помещен в функцию, не принимающую параметры. Так было бы лучше сделать это во всех функциях C++, которые не имеют параметров? - person Paul Renton; 16.08.2013
comment
@AdrianMcCarthy: MVP вряд ли проблема. - person Lightness Races in Orbit; 30.05.2014
comment
@AdrianMcCarthy Я не думаю, что проблема MVP была бы решена. Как насчет std::vector<int> v(std::vector<int>()); или любой комбинации двух типов, построение одного непосредственно в конструкторе другого. - person Yam Marcovic; 27.05.2015
comment
@ chacham15 void foo() { if ( rand() ) foo(5); } компилируется и запускается (вызывая неопределенное поведение, если вам не очень повезло), тогда как void foo(void) с тем же телом вызовет ошибку компиляции. - person M.M; 23.12.2015
comment
@MatthieuM. это интересная информация. Я хотел бы иметь ссылку, чтобы прочитать вопрос/текст, который вы упомянули. Да, я знаю, 7 лет спустя, ха-ха - person JohnTortugo; 25.03.2018
comment
extern C void foo(void) НЕ требуется, так как функции являются внешними по умолчанию и по самой своей природе :) - person Sammy; 02.08.2018
comment
Если вы хотите, чтобы ваш компилятор C++ применял правила изменения имен C к объявлениям C — а вы это делаете, если вы хотите, чтобы компоновщик знал, о чем вы говорите, — тогда вам нужно extern "C" вокруг имен C. - person DrPizza; 10.08.2018
comment
@MM Вы не можете вызвать неопределенное поведение. Либо программа имеет четко определенное поведение, либо нет. Это свойство, а не событие. Однако, если вы видите странные вещи, происходящие в результате выполнения программы, поведение которой не определено, зависит от случая; возможно вы это имели в виду? - person Asteroids With Wings; 21.01.2021
comment
@AsteroidsWithWings Может быть и то, и другое. Другой пример, аналогичный вышеприведенному, — if (getchar() == 'x') 1/0; , поведение не определено только в том случае, если выполнение достигает этой строки и дается определенный ввод. - person M.M; 21.01.2021
comment
@MM Это все еще свойство программы; казалось, что вы смешиваете неопределенное поведение с возможными странными симптомами неопределенного поведения, поскольку вы утверждали, что можете каким-то образом избежать этого, если вам очень повезет (что неверно в данном примере, если исходный код не изменится!) - person Asteroids With Wings; 21.01.2021
comment
@AsteroidsWithWings Элемент удачи зависит от возвращаемого значения rand(); если происходит возврат 0, то неопределенного поведения нет: наличие foo(5) в коде, который никогда не выполняется, не означает, что программа имеет UB. Я не путаю УБ с симптомами УБ. Возможно, пример getchar() лучше, чем пример rand(), чтобы продемонстрировать этот момент, чтобы избежать споров о гарантиях последовательности чисел, сгенерированных rand() - person M.M; 21.01.2021
comment
@М.М. О, честно :Р - person Asteroids With Wings; 21.01.2021

Я понимаю, что ваш вопрос относится к C++, но когда дело доходит до C, ответ можно найти в K&R, страницы 72-73:

Кроме того, если объявление функции не включает аргументы, как в

double atof();

это также означает, что ничего не следует делать в отношении аргументов atof; проверка всех параметров отключена. Это специальное значение пустого списка аргументов предназначено для того, чтобы старые программы на C могли компилироваться новыми компиляторами. Но использовать его с новыми программами — плохая идея. Если функция принимает аргументы, объявите их; если он не принимает аргументов, используйте void.

person Kyle Cronin    schedule 09.09.2008
comment
Но вопрос касается определений, в этом случае соответствующее правило C: Пустой список в деклараторе функции, который является частью определения этой функции, указывает, что функция не имеет параметров. - person jinawee; 26.12.2018

Черновик стандарта C++11 N3337

Нет никакой разницы.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

Приложение C "Совместимость" C.1.7 Пункт 8: деклараторы гласит:

8.3.5 Изменение: В C++ функция, объявленная с пустым списком параметров, не принимает аргументов. В C пустой список параметров означает, что количество и тип аргументов функции неизвестны.

Пример:

int f();
// means int f(void) in C ++
// int f( unknown ) in C

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

Влияние на исходный признак: изменение семантики четко определенного признака. Эта функция была отмечена как «устаревшая» в C.

Функции 8.5.3 говорит:

4. Предложение-объявления-параметра определяет аргументы, которые могут быть указаны, и их обработку при вызове функции. [...] Если предложение объявления параметра пусто, функция не принимает аргументов. Список параметров (void) эквивалентен пустому списку параметров.

C99

Как упоминалось в С++ 11, int f() ничего не указывает на аргументы и устарело.

Это может привести либо к рабочему коду, либо к UB.

Я подробно интерпретировал стандарт C99 по адресу: https://stackoverflow.com/a/36292431/895245.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 25.04.2016

В C вы используете пустоту в пустой ссылке на функцию, так что у компилятора есть прототип, и этот прототип не имеет «аргументов». В C++ вам не нужно сообщать компилятору, что у вас есть прототип, потому что вы не можете пропустить прототип.

person Paul Tomblin    schedule 09.09.2008
comment
прототип означает объявление списка аргументов и возвращаемый тип. Я говорю это, потому что прототип сначала смутил меня относительно того, что вы имели в виду. - person Zan Lynx; 01.10.2008