Является f (void), устаревшим в современных C и С++

В настоящее время я реорганизую/убираю старый код C, используемый в проекте на С++, и регулярно вижу такие функции, как:

int f(void)

который я хотел бы написать как:

int f()

Есть ли какая-либо причина не заменять (void) на() на всей кодовой базе, чтобы улучшить согласованность, или есть тонкая разница между двумя, о которых я не знаю? Более конкретно, если функция виртуального члена в С++ описывается как:

virtual int f(void)

а производный класс включает функцию-член:

int f()

- это допустимое переопределение? Кроме того, могу ли я столкнуться с любыми проблемами компоновщика, основанные на почти идентичных сигнатурах?

Ответ 1

В C объявление int f(void) означает функцию, возвращающую int, которая не принимает никаких параметров. Объявление int f() означает функцию, возвращающую int, которая принимает любое количество параметров. Таким образом, если у вас есть функция, которая не принимает никаких параметров в C, первый является правильным прототипом.

В С++ я считаю, что int f(void) устарел, а int f() является предпочтительным, поскольку он специально означает функцию, которая не принимает никаких параметров.

Ответ 2

Чтобы добавить к Крису ответ, использование int f() - это плохая практика в C, по моему опыту, поскольку вы теряете способность компилятора сравнивать объявление функции с ее определением, чтобы убедиться, что он будет вызван правильно.

Например, следующий код соответствует стандарту C:

#include <stdio.h>
void foo();
void bar(void) {
    foo();
}
void foo(int a) {
    printf("%d\n", a);
}

Но это приводит к поведению undefined, поскольку a не передается в foo.

В С++ существуют две версии foo: одна, которая не принимает аргументов, а другая принимает int. Таким образом, bar завершает вызов версии undefined, что приведет к ошибке компоновщика (при условии, что в нем нет других определений foo).

Ответ 3

Ответы, приведенные выше, вполне правильны, но я связываюсь с превосходной страницей Дэвида Триббла, поскольку она дает отличное объяснение по этому и многим другим вопросы.

Основные моменты:

C различает функцию объявлен с пустым списком параметров и функцию, объявленную с помощью список параметров, состоящий только из недействительным. Первый - непрототированный функция с неуказанным номером аргументов, в то время как последний является прототипированная функция без Аргументы.

С++, с другой стороны, не делает различие между этими двумя декларации и рассматривает их как означает функцию, не Аргументы.

Для кода, который должен быть скомпилированный как C или С++, лучший решение этой проблемы - всегда объявлять функции без параметров с явным прототипом пустоты.

Пустые прототипы функций являются устаревшая функция на C99 (поскольку они были в C89).

Изменить: посмотрев на стандарт, возможно, стоит отметить, что синтаксис func (void) не устарел на С++, но он обычно считается более похожим на идиому C-стиля. Я думаю, что большинство программистов на С++, с которыми я столкнулся, предпочитают пустой список параметров.

Изменить 2: добавление цитаты из стандарта С++, раздел 8.3.5, пункт 2:

"Если предложение параметра-объявления пусто, функция не принимает аргументов. Список параметров (void) эквивалентен списку пустых параметров. За исключением этого специального случая, void не должен быть типом параметра (хотя типы полученный из void, такой как void *, can).

Не упоминается, что любая форма устарела. Еще раз спасибо г-ну Трибблу за отличный сайт, указав мне правильный раздел стандарта.

Ответ 4

tl; dr: используйте void.

Учитывая обратную совместимость в С++ и бит двусмысленности, указанный ниже, я утверждаю, что мы вернемся к KnR и ANSI C для окончательного ответа:

int getline(void);
int copy(void)

Поскольку специализированные версии getline и copy не имеют аргументов, логика предполагает, что их прототипы в начале файла должен быть getline() и copy(). Но для совместимости с более старые программы C, стандарт принимает пустой список как старомодный объявление и отключает проверку списка всех аргументов; слово void должен использоваться для явно пустого списка. [Керниган и Ричи, язык программирования C, 1988, стр. 32-33]

и..

Особый смысл списка пустых аргументов более старые C-программы для компиляции с новыми компиляторами. Но это плохая идея использовать его с новыми программами. Если функция принимает аргументы, объявляйте их; если он не принимает аргументов, используйте void [ibid, Pg. 73]

РЕДАКТИРОВАТЬ: Разрушить остальное в отдельном обсуждении здесь: Указывает ли использование void в объявлении функции, которая не принимает аргументов, выдает самый большой аргумент Vexing?

Ответ 5

стандартный сценарий C11 N1570

void f() не рекомендуется, void f(void) рекомендуется

6.11.6 Объявление функций:

1 Использование деклараторов функций с пустыми круглыми скобками (а не параметром прототипа тип деклараторы) является устаревшей особенностью.

Введение:

2 Некоторые функции устаревают, а это означает, что они могут рассматриваться как отмена в будущем пересмотра настоящего международного стандарта. Они сохраняются, потому что их широкого использования, но их использование в новых реализациях (для реализации функции) или новые программы (для языка [6.11] или функций библиотеки [7.31]) не рекомендуется.

Подробное обсуждение: fooobar.com/questions/22916/...

С++ 11 Стандартная черновая версия N3337

Ни void f(void), ни void f() не устарели.

void f(void) существует для совместимости с C. Приложение C "Совместимость" C.1.7 Пункт 8: деклараторы:

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

Так как void f() не рекомендуется в C и void f(void) рекомендуется, void f(void) будет существовать до тех пор, пока С++ хочет поддерживать совместимость.

void f(void) и void f() одинаковы в С++. Поэтому более длинный void f(void) имеет смысл только в том случае, если вы заботитесь о написании кода, который компилируется под C и С++, что, вероятно, не стоит.

Подробное обсуждение: fooobar.com/questions/32941/...

Ответ 6

В С++ int f (void) действительно является устаревшим объявлением, которое на 100% эквивалентно int f(). Это та же подпись. void в этом контексте имеет такое же значение, как, например, пробельные. Это также означает, что они подчиняются Правилу одного определения (они не перегружают), а Derived:: f (void) переопределяет Base:: f()

Не вмешивайтесь в такие вещи, как f (const void). Там не так много консенсуса, что означает эта странность.