#cpp
Чем отличается объявление функции int main(){} От int main(void){} ? Вроде все то же самое, но часто попадается в исходниках последнее. Если нет разницы, зачем писать лишнее?
Ответы
Ответ 1
void foo(void); Это правильный путь объявления функции без параметров в С, С++. С другой стороны: void foo(); Имеет разное значение в С и С++! В С это означает "может принимать любое количество параметров неизвестных типов", в С++ имеет тот же смысл что и foo(void). Функции с переменным количеством аргументов по своей сути являются небезопасными, и их следует избегать, когда это только возможно. SourceОтвет 2
Предлагаю разобраться с подобным синтаксисом. В языке C функция может быть объявлена как 6.7.6.3 Function declarators (including prototypes If, in the declaration "T D1",D1 has the form D(parameter-type-list) or D(identifier-list_opt) Как видим, у нас имеется два варианта объявления: В скобках parameter-type-list В скобках identifier-list При этом parameter-type-list является обязательным, а identifier-list является опциональным (_opt). Теперь взглянем на то, что же такое identifier-list: An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied. То есть функция с identifier-list это вот такое объявление: void foo(a, b, c) int a, b, c;//Функция объявлена с identifier-list При этом такое объявление не накладывает ограничений на тип и количество параметров при вызове. Также, такой список является опциональным, т.е. может отсутствовать. void foo();//Функция с пустым identifier-list А это значит, что при вызове такой функции можно передавать параметры разных типов в разном количестве, т.е. вызовы foo() или foo(1, 2) являются законными. Перейдем к parameter-type-list: A parameter type list specifies the types of, and may declare identifiers for, the parameters of the function. это список типов параметров, и, возможно, идентификаторов: void foo(char, int, float x);//Функция объявлена с parameter-type-list Смотрим стандарт далее: The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters. То есть имеется специальный случай для объявления функции не принимающей параметров - один параметр типа void без имени: void foo(void);//Функция без параметров Для такой функции вызов foo(1, 2) уже не является правильным, в отличии от ситуации с identifier-list. Теперь, что касается C++. В C++ имеется один вариант объявления функции: In a declaration T D where D has the form D1 ( parameter-declaration-clause ) cv-qualifier-seq_opt ref-qualifier_opt noexcept-specifier_opt attribute-specifier-seq_opt trailing-return-type При этом имеется правило: ... If the parameter-declaration-clause is empty, the function takes no arguments. A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list. То есть для C++ объявления void foo(); void foo(void); полностью эквивалентны. И немного истории. Выдержка из книги Бьёрна Страуструпа "Дизайн и эволюция C++": В C with Classes введена нотация f(void) для функции f(), не принимающей аргументов, вместо нотации f() в C, обозначающей функцию с любым числом аргументов без проверки типов. Однако вскоре пользователи убедили меня, что нотация f(void) неизящна, а объявление с помощью f() функции, которая может принимать аргументы, далеко от интуитивно очевидного. Поэтому после некоторых экспериментов было решено оставить нотацию f() для функции, не принимающей никаких аргументов, ибо именно этого ожидает неискушенный пользователь. Чтобы отважиться на такой разрыв с традициями C, мне потребовалась поддержка со стороны Дуга Макилроя и Денниса Ритчи. Только после того как они охарактеризовали нотацию f(void) словом "гадость", я решил придать f() очевидную семантику. Однако и по сей день правила контроля типов в C гораздо слабее чем в C++, а комитет по стандартизации ANSI C одобрил "отвратительную f(void)", впервые появившуюся в C with Classes.Ответ 3
Чтобы компилятор не ругался, по стандарту, должны быть описаны параметры принимаемые функцией, если их нет то void - пусто/отсутствие параметров. Попробуйте собрать код без void с ключами -Wall -Wextra -pedantic, для C языка полезен ключ -Wstrict-prototypes (gcc или clang) и увидите реакцию компилятора. Вероятно будет полезно ознакомиться с ключами компилятора, чтоб получать больше информации о собственном коде. например важные ключи для анализа собственного кода: -Wall Включите все предупреждения о конструкциях, которые некоторые пользователи считают сомнительными, и которые легко избежать (или изменить для предотвращения предупреждения), даже в сочетании с макросами, другими словами, некоторый набор предупреждений. -Wpedantic Выдать все предупреждения, требуемые строгими ISO C и ISO C ++; отклонить все программы, которые используют запрещенные расширения, и некоторые другие программы, которые не соответствуют ISO C и ISO C ++. -Wextra более полный тест собираемого кода, включены максимально возможные предупреждения, но некоторые предупреждения задаются только индивидуально. -Weverything специфический флаг компилятора clang, после его включения иногда возникает желание удалить написанное :) -Werror -pedantic-errors -Werror выдает ошибку, когда обнаружено предупреждение, переводит warnings в errors, -pedantic-errors соответственно делает тоже самое, только для предупреждений доступных в -pedantic mode. Историческая справка: Первоначально C-функции не имели прототипов, поскольку C эволюционировал из B, беспристрастного языка :) . Когда были добавлены прототипы, оригинальные декларации без текста были оставлены на языке для обратной совместимости.
Комментариев нет:
Отправить комментарий