Номер
Согласно нормативной формулировке стандарта определение с использованием пустых круглых скобок без ключевого слова void
не является одной из форм , которые должны быть приняты, и, строго говоря, поведение такая программа не определена.
Код: N1570 раздел 5.1.2.2.1. (Опубликованная 2011 ISO C стандарт, который не является в свободном доступе, имеет ту же формулировку, как и проект N1570.)
Пункт 1 говорит:
Функция называется при запуске программы называется main
, Реализация объявляет прототип для этой функции.Она должна быть определена с типом возвращаемого int
и без каких-либо параметров:
int main(void) { /* ... */ }
или с двумя параметрами (называемый здесь argc
и argv
, хотя любые имена могут быть использованы, поскольку они являются локальными для функции, в которой они объявлены):
int main(int argc, char *argv[]) { /* ... */ }
или его эквивалент; или каким-либо другим способом реализации.
Использование слова «должно» вне ограничения означает, что любая программа , которая ее нарушает, имеет неопределенное поведение. Так что если, например, я пишу:
double main(unsigned long ocelots) { return ocelots/3.14159; }
конформный компилятор не требуется для печати диагностики, но это также не требуется либо скомпилировать программу или, если она компилируется его, чтобы иметь он ведет себя определенным образом.
Если int main()
были эквивалент к int main(void)
, то будет действительным и переноситься на любую размещенную соответствующей реализации. Но это не эквивалентно.
int main(void) { }
обеспечивает как декларацию (в данном случае, прототип) и определение. Объявление, используя ключевое слово void
, указывает, что функция не имеет параметров. Определение определяет одно и то же.
Если я вместо этого написать:
int main() { }
тогда я использую старого стиля объявление и определение. (Такие декларации и определения устаревшее, но они до сих пор часть определения языка, и все соответствующие компиляторы должны до сих пор поддерживают их.)
В декларации, она не указывает номер или тип (ы) аргументов , ожидаемый функцией. В качестве определения он не определяет никаких параметров, , но компиляторы не должны использовать эту информацию для диагностики неправильных вызовов.
DR #317 включает в себя 2006 постановления комитета по стандартам в C, что определение с ()
не обеспечивает прототип, эквивалентные одному с (void)
(благодаря HVd для поиска, что ссылка).
C Позволяет main
называться рекурсивно.Предположим, что я пишу:
int main(void) {
if (0) {
main(42);
}
}
Видимая прототип int main(void)
указывает, что main
не принимает аргументов. Вызов, который пытается передать один или несколько аргументов , нарушает ограничение, требующее диагностики времени компиляции.
Или предположим, что я пишу:
int main() {
if (0) {
main(42);
}
}
Если вызов main(42)
были выполнены, он будет иметь неопределенное поведение - но это не нарушает ограничений, и никаких диагностических не требуется. Поскольку он защищен if (0)
, вызов никогда не произойдет, и неопределенное поведение никогда не происходит. Если мы предположим, что int main()
действителен, то эту программу необходимо принять любым соответствующим компилятором . Но из-за этого он демонстрирует, что int main()
: не, эквивалентный int main(void)
, и поэтому не подпадает под действие 5.1.2.2.1.
Вывод: После формулировки стандарта, реализаций разрешаются документально подтвердить, что int main() { }
является допускается. Если он не документирует его, он все равно может принять без жалобы. Но соответствующий компилятор может также отклонить int main() { }
, поскольку он не является одним из форм, разрешенных стандартом , и поэтому его поведение не определено.
Но есть еще открытый вопрос: было ли это намерение авторов стандарта?
До публикации стандарта ANSI C 1989 года ключевого слова void
не существовало. Предварительно ANSI (K & R) программы C будет определять main
либо
main()
или
int main()
Основная цель стандарта ANSI, чтобы добавить новые функции (в том числе прототипов) без нарушение существующего кода pre-ANSI. Заявив, что int main()
не действует, было бы нарушением этой цели.
Мое подозрение в том, что авторы стандарта C не намерены сделать int main()
недействительным. Но стандарт, как написано, не отражает это намерение; он по крайней мере разрешает соответствующий компилятор C отклонить int main()
.
Практически Говоря, вы можете почти наверняка уйти от него. Каждого C компилятор, который я когда-либо пробовал буду принимать
int main() { return 0; }
без жалоб, с поведением, эквивалентного
int main(void) { return 0; }
Но по целому ряду причин:
- После буквы и цель стандарта;
- Избегайте использования устаревшей функции (будущий стандарт может удалить определения функций старого стиля);
- Поддержание хороших привычек кодирования (разница между
()
и (void)
имеет важное значение для других, чем main
функций, которые на самом деле называются другими функциями
Я рекомендую всегда писать int main(void)
, а не int main()
. Он утверждает намерение более ясно, и вы можете быть 100% уверены, что ваш компилятор будет принимать его, а не 99,9%.
Я хотел добавить что-то так плохо; которые выросли в дни менее компиляторов и обучаемых, написанных для них; но, действительно, вы полностью покрыли эту землю :) –
Это действительно хороший ответ! Спасибо за то, что вы тоже поделились этим примером! –
Следует отметить, что любые нарушения в этом случае относительно бессмысленны, если вы не используете переданные параметры и объявляете «нормальный» (то есть размер регистра). Любое несоответствие стека происходит только после возвращения 'main', после чего ваша программа уже завершена. – Blindy