Каково было обоснование того, что `return 0` в конце` main` опционально?

Начиная со стандарта C99, компилятор должен генерировать эквивалент return 0 или return EXIT_SUCCESS, если в конце main возврат невозможен. В то же время было также соответствующее и идентичное изменение для языка С++. Меня интересуют причины обоих, и я догадался, что вряд ли они были бы совершенно отдельными и несвязанными изменениями.

Мой вопрос:

Каково было документированное обоснование этого изменения?

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

Обратите внимание, что в отличие от вопроса Какие причины для возврата 0 из основного в ISO С++?, я не прошу совета о том, писать ли return 0 в моих программах - я спрашиваю, почему сами языковые стандарты были изменены.


Чтобы понять цель вопроса, вот немного больше контекста:

  • Понимание того, почему было сделано изменение, полезно при принятии решения о его использовании.
  • Обоснование часто включается в сам стандарт. Например, стандарт C90 включает в себя множество пояснительных сносок, таких как сноска 36, которая начинается: "Цель этого списка..."

Я изучил стандарты, которые искали ответ, прежде чем я спросил здесь, но не нашел ответа. Меня попросили помочь написать стандарты кодирования для обоих языков для группы программистов, и я хотел убедиться, что я понимаю, почему эта функция существует, чтобы я мог точно объяснить ее использование другим.

Ответ 1

В Новый стандарт C 5.1.2.2.3 Окончание программы автор Derek Jones комментарий по этим строкам из стандарта C99:

достигая}, который завершает основную функцию, возвращает значение 0

является:

Стандарт, наконец, должен поклониться небрежным существующим практикам.

Это указывает на то, что логическое обоснование заключалось в том, чтобы устранить неправильные методы программирования в отношении явного возврата значения из main. До этого возвращался статус undefined.

Он указывает, что многие реализации уже реализовали это даже в C90, поэтому, вероятно, также помог тот факт, что это изменение уже отразило общую реализацию.

Ответ 2

официальный документ обоснования для C99 вряд ли справится с этим. Похоже, что exit(0) стал по умолчанию для потока управления с конца основного, потому что exit(0) была предоставлена ​​значимая переносная семантика.

Вот два соответствующих раздела:

5.1.2.2.1 Запуск программы

Поведение аргументов main и взаимодействия exit, main и atexit (см. §7.20.4.2) было кодифицировано для ограничения некоторого нежелательного многообразия в представлении строк argv и в значении значений, возвращаемых main.

Спецификация argc и argv в качестве аргументов main признает обширную предыдущую практику.

argv[argc] должен быть нулевым указателем, чтобы обеспечить избыточную проверку для конца списка, также на основе обычной практики.

main - единственная функция, которую можно условно объявить либо с нулевым, либо с двумя аргументами. (Число аргументов других функций должно точно совпадать между вызовом и определением.) Этот специальный случай просто распознает распространенную практику отказа от аргументов main, когда программа не получает доступ к строкам аргумента программы. Хотя многие реализации поддерживают более двух аргументов main, такая практика не является ни благословенной, ни запрещенной Стандартом; программа, определяющая main с тремя аргументами, не является строго (см. §J.1.1.).

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

и

7.20.4.3 Функция выхода

Аргумент exit - это индикатор состояния, возвращаемый вызывающей среде. В операционной системе UNIX значение нуля - это успешный код возврата из программы. Поскольку использование C распространяется за пределы UNIX, exit(0) часто сохранялось как идиома, указывающая на успешное завершение, даже в операционных системах с различными системами кодов возврата. Таким образом, это использование признанных стандартными. Никогда не было переносного способа указания неудачного завершения, поскольку аргументы exit определены реализацией. Макрос EXIT_FAILURE был добавлен в C89, чтобы обеспечить такую ​​возможность. EXIT_SUCCESS.

Помимо вызовов, явно закодированных программистом, при возврате из main вызывается exit. Таким образом, по крайней мере в этом случае тело exit не может предполагать существование каких-либо объектов с автоматическим временем хранения, кроме тех, которые указаны в exit.

Комитет рассмотрел вопрос о добавлении _exit, но отклонил его, исходя из соображений несовместимости с спецификацией POSIX, на которой он основан. Например, одна проблема заключается в том, что _exit был указан как способ выйти из обработчика сигнала без запуска другого сигнала, но на самом деле это не так, как _exit ведет себя в среде POSIX. Комитет не хотел давать программистам такую ​​ложную надежду. (Но см. §7.20.4.4 для C99.)