Почему `main` не может возвращать double или String, а не int или void?

38

Во многих языках, таких как C, C ++ и Java, mainметод / функция имеет возвращаемый тип voidили int, но не doubleили String. Какие могут быть причины этого?

Я немного знаю, что мы не можем этого сделать, потому что он mainвызывается из библиотеки времени выполнения, и он ожидает некоторый синтаксис, такой int main()или int main(int,char**)около того, что мы должны придерживаться этого.

Итак, мой вопрос: почему у него mainесть сигнатура типа, а не другая?

ДЖАВА
источник
19
Что будет означать двойное возвращаемое значение ? Что бы возвращаемое значение строк означает ?
1
Я понимаю, что это ничего не значит. Но есть ли другие причины и условности?
JAVA
1
Я думаю, это ничего не значит, просто потому, что универсально было выбрано, что 0 для нормального выхода и ненулевое значение для ненормального. В качестве простейшего типа данных с широкой межязыковой совместимостью был выбран int. @ delnan
JAVA
@sunny Из того, что я смог извлечь из своего опыта работы с Unix-подобными ОС, 0 используется как «нормальный выход» (0 ошибок), потому что это однозначно по сравнению с другими целочисленными значениями. Так как большинство (не все) современных языков спроектированы так, чтобы быть похожими (если не спроектированы на задней стороне) C, и поскольку C использовался для написания Unix, я бы сказал, что это было историческое решение KnR.
Джейми Тейлор
3
@sunny "широкая межязыковая совместимость" не была проблемой. C и UNIX были написаны в тандеме. Причина, по которой многие другие языки возвращают int, заключается в том, что они были разработаны для работы в UNIX или UNIX-подобных средах.

Ответы:

88

Возвращаемое значение mainдолжно передаваться в операционную систему ( любую операционную систему) одним последовательным способом. Информация, которую должна знать операционная система: «Программа успешно завершилась или произошла ошибка?»

Если это строка, ответ становится трудным на разных языках. Внутренние элементы строки Паскаля (первый байт равен длине) и строка FORTRAN (фиксированная, дополненная некоторым значением) и строка C (завершенная нулем) - все разные. Это усложнит возвращение непротиворечивого значения операционной системе. Предполагая, что это было решено, что бы вы сделали, чтобы ответить на вопрос, который была у ОС программы? Сравнение строк чревато ошибками («успех» или «успех»), и, хотя ошибка может быть более полезной для человека, для операционной системы или другой программы (оболочки) труднее иметь дело. Также были значительные различия даже в самих строках - EBCDIC (со всеми его кодовыми страницами) и ASCII.

Число с плавающей запятой и двойное число не предоставляют дополнительного значения по сравнению с целым числом для обратной передачи данных в ОС (и оболочку). По большей части, ни одна из этих частей компьютера не имеет дело с числами с плавающей запятой. Двойники также не перечисляются, что затрудняет сравнение. Не будучи перечисляемыми, они создают отчет об ошибке (при условии, что вы выбрали конкретное значение для успеха). Опять же, числа с плавающей запятой не согласованы - число с плавающей запятой на 8-битной машине отличалось от числа с плавающей запятой на 16-битной и 32-битной машине (и это только «нормальные» значения - даже в IBM плавающая точка не была стандартизирована между машинами одного и того же производителя до 1980-х годов). И тогда у вас есть десятичные против двоичных компьютеров. Значения с плавающей запятой не согласованы и не дают значимых данных обратно.

Это действительно оставляет нас с байтом и целым числом в качестве параметров. Соглашение, которое было установлено, было «0», было успехом, и все остальное было ошибкой. Целое число дает больше места, чем байт, для сообщения об ошибке. Он может быть перечислен (возврат 1 означает XYZ, возврат 2 означает ABC, возврат 3, означает DEF и т. Д.) Или может быть использован как флаг ( 0x0001означает, что это не удалось, 0x0002означает, что произошел сбой, 0x0003означает и то, и другое). Ограничение всего лишь одним байтом может легко исчерпать флаги (только 8), поэтому решение, вероятно, заключалось в использовании целого числа.

Шон Оллред
источник
2
Я думаю, что main вызывается библиотекой времени выполнения c / c ++, прежде чем os вызывает ее, которая также является фрагментом кода, загружаемым вместе с нашим кодом и вызываемым os @ MichaelT
JAVA
5
main()вызывается по-разному в разных операционных системах. В C как изначально вызывается метод main ()? идет в это.
25
Я думаю, что ключевой момент, который нужно понять, заключается в том, что main- в отличие от других функций в любой программе - это не часть протокола, определенного программистом, а протокол, используемый для взаимодействия с хостом (ОС). Вы не можете выбрать это, потому что это никогда не было вашим выбором. На более прагматичном уровне UNIX ожидает, что процесс вернет int, и протокол C-to-UNIX делает именно это. Аналогичный аргумент может быть сделан для передачи аргументов: если бы C был изобретен для ОС / хоста, который передавал только числа в качестве аргументов (например, без командной строки), аргументы были бы целыми числами вместо строк.
Евро Мицелли
2
IBM перенесла концепцию кодовых страниц из EBCDIC на свои ПК. Они все еще преследуют нас сегодня, спустя 35 лет после появления IBM 5150. 7-битный ASCII не содержит кодовых страниц , но 8-битные коды символов можно интерпретировать по-разному даже на одном компьютере, в зависимости от настроек - - не говоря уже о кодовых страницах, которые кодируют для многобайтовых кодировок. Так что на самом деле это даже хуже, чем то, на что вы ссылаетесь в последнем предложении второго абзаца.
CVn
@EuroMicelli это очень хорошая информация, на самом деле спасибо за это :)
JAVA
29

Ну, это может .

Например, на диалекте C, используемом в операционной системе Plan 9main , обычно объявляется как voidфункция, но состояние выхода возвращается в вызывающую среду путем передачи строкового указателя на exits()функцию. Пустая строка обозначает успех, а любая непустая строка обозначает какой-то сбой. Это может быть реализовано при наличии mainвозвращать char*результат.

И, конечно, было бы возможно реализовать систему со статусом floatили doubleвыход.

Так почему же int? Это просто вопрос соглашения - и есть огромная ценность в том, чтобы операционные системы и программы, работающие под ними, подчинялись общему соглашению.

Соглашение Unix состоит в том, чтобы использовать целочисленный код состояния, где 0 означает успех, а ненулевое - отказ (потому что обычно есть только один способ добиться успеха, но несколько способов потерпеть неудачу). Я не знаю, возникла ли эта конвенция с Unix; Я подозреваю, что это произошло от более ранних операционных систем.

Соглашение с плавающей точкой будет более сложным соглашением, поскольку (а) поддержка с плавающей точкой не является универсальной, (б) сложнее определить отображение между значениями с плавающей точкой и условиями ошибки, (в) разные системы используют разные плавающие представление точек и (d) просто представьте себе удовольствие от отслеживания ошибки округления в состоянии выхода вашей программы. Целые числа, с другой стороны, очень хорошо подходят для перечисления кодов ошибок.

В Plan 9, как я уже упоминал, используются строки, но это усложняет управление памятью, кодировку символов и т. Д. Насколько мне известно, идея, появившаяся в Plan 9, была новой, и она не заменила существующую. широко распространенная конвенция.

(Между прочим, в C ++ mainможно только возвращать int, а в C void mainэто разрешено только в том случае, если компилятор специально его поддерживает. Многие компиляторы не очень громко жалуются, если вы пишете void main, но это лишь небольшое преувеличение, чтобы сказать, что это неправильно .)

Кит Томпсон
источник
9

Значение, возвращаемое методом main, является «кодом выхода». Он используется приложением вызывающей стороны (обычно bash) для проверки, закончилась ли программа ожидаемым образом. Возврат целого числа - это самый простой способ сделать это на уровне ОС. Double не имеет смысла для кода ошибки, а String трудно поддерживать на уровне ОС (GC отсутствует).

xeranic
источник
3
Почему строку нужно собирать мусором, а целое - нет?
Брэд
4
@Brad, строки имеют переменную длину и будут по сути аналогичны передаче массива, который может быть одним символом или тысячами. Динамическая память была бы проблемой, в то время как int - довольно фиксированный размер, с которым не так сложно справиться.
JB King
-4

Функция main должна возвращать статус программы, которая выполняется. Независимо от того, выполняется ли она успешно (возвращает 0, то есть EXIT_SUCCESS) или нет (возврат 1 означает EXIT_FAILURE), любое ненулевое число передает то же значение, но ноль указывает на отсутствие ошибок или успешного выполнения.

дилеепкумар р
источник
1
это, кажется, не предлагает ничего существенного по сравнению с замечаниями, сделанными (и гораздо лучше объясненными) в предыдущих ответах, которые были опубликованы несколько лет назад
коммент