¿Por qué no puede `main` devolver un double o String en lugar de int o void?

38

En muchos lenguajes como C, C ++ y Java, el mainmétodo / función tiene un tipo de retorno de voido int, pero no doubleo String. ¿Cuáles podrían ser las razones detrás de eso?

Sé un poco que no podemos hacer eso porque maines invocado por la biblioteca de tiempo de ejecución y espera alguna sintaxis como int main()o int main(int,char**)así, tenemos que apegarnos a eso.

Entonces mi pregunta es: ¿por qué maintiene la firma de tipo que tiene, y no una diferente?

JAVA
fuente
19
¿Cómo sería un valor de retorno doble significa ? ¿Cómo sería una cadena de valor de retorno significa ?
1
entiendo que no significa nada, pero ¿alguna otra razón y convenciones?
JAVA
1
creo que no significa nada, simplemente porque universalmente se eligió ese 0 para la salida normal y un cero para un anormal. Se eligió un int como el tipo de datos más simple con una amplia compatibilidad entre idiomas. @ delnan
JAVA
@sunny De lo que he podido deducir de mi experiencia con sistemas operativos tipo Unix, 0 se usa como una "salida normal" (0 errores) porque no es ambiguo en comparación con otros valores enteros. Dado que la mayoría (no todos) los lenguajes modernos están diseñados para ser similares a (si no están diseñados en la parte posterior de) C, y dado que C se usó para escribir Unix, diría que fue una decisión histórica de KnR.
Jamie Taylor
3
@sunny "amplia compatibilidad entre idiomas" no fue un problema. C y UNIX se escribieron en tándem. La razón por la que muchos otros idiomas devuelven ints es porque fueron diseñados para funcionar en entornos UNIX o similares a UNIX.

Respuestas:

88

El valor de retorno de mainse debe pasar al sistema operativo ( cualquier sistema operativo) de una manera única y coherente. La información que el sistema operativo necesita saber es "¿el programa finalizó correctamente o hubo un error?"

Si se trata de una cadena, la respuesta se vuelve difícil en diferentes idiomas. Las partes internas de una cadena Pascal (primer byte es la longitud) y una cadena FORTRAN (fija, rellenada con algún valor) y una cadena C (terminada en nulo) son todas diferentes. Esto haría que devolver un valor constante al sistema operativo fuera un desafío. Suponiendo que esto se resolvió, ¿qué haría para responder la pregunta que el sistema operativo tenía sobre el programa? Las comparaciones de cadenas están llenas de errores ("éxito" versus "éxito"), y aunque el error puede ser más útil para un humano, es más difícil de manejar para el sistema operativo u otro programa (shell). También hubo diferencias significativas incluso en las propias cadenas: EBCDIC (con todas sus páginas de códigos) frente a ASCII.

Los flotantes y los dobles no proporcionan ningún valor adicional sobre el entero para comunicar los datos al sistema operativo (y al shell). En su mayor parte, ninguna de estas partes de la computadora trata con números de coma flotante. Los dobles tampoco son enumerables, lo que dificulta las comparaciones. Al no ser enumerables, informan cuál fue el error (suponiendo que haya elegido un valor particular para el éxito). Una vez más, los puntos flotantes no son consistentes: un flotante en una máquina de 8 bits era diferente del flotante en una máquina de 16 bits y una de 32 bits (y esos son solo los 'normales', incluso dentro de IBM, el punto flotante no estaba estandarizado entre máquinas del mismo fabricante hasta la década de 1980). Y luego tienes computadoras decimales vs. binarias. Los valores de coma flotante no son consistentes y no devuelven datos significativos.

Eso realmente nos deja con el byte y el entero como opciones. La convención que se estableció fue '0' fue un éxito, y cualquier otra cosa fue un error. Un número entero da más espacio que un byte para informar el error. Se puede enumerar (el retorno de 1 significa XYZ, el retorno de 2 significa ABC, el retorno de 3, significa DEF, etc.) o usarse como indicadores ( 0x0001significa que esto falló, 0x0002significa que falló, 0x0003significa tanto esto como aquello que falló). Limitar esto a solo un byte podría quedarse sin banderas (solo 8), por lo que la decisión fue probablemente usar un número entero.

Sean Allred
fuente
2
Creo que main es llamado por la biblioteca de tiempo de ejecución c / c ++ antes de que lo llamemos, que también es un fragmento de código cargado junto con nuestro código y llamado por os @ MichaelT
JAVA
55
main()se invoca de diferentes maneras en diferentes sistemas operativos. En C, ¿cómo se llama inicialmente el método main ()? entra en esto.
25
Creo que el punto clave a entender es que main, a diferencia de otras funciones en cualquier programa, no es parte de un protocolo definido por el programador, sino el protocolo utilizado para interactuar con el host (SO). No puedes elegirlo porque nunca fue tuyo. En un nivel más pragmático, UNIX espera que un proceso devuelva un int, por lo que el protocolo C-a-UNIX hace exactamente eso. Se puede hacer un argumento análogo para pasar argumentos: si C se hubiera inventado para un sistema operativo / host que pasara solo números como argumentos (por ejemplo, sin línea de comandos), los argumentos serían ints en lugar de cadenas.
Euro Micelli
2
IBM llevó el concepto de páginas de códigos de EBCDIC a sus PC. Todavía nos persiguen hoy, 35 años después de la introducción del IBM 5150. El ASCII de 7 bits no tiene código, pero los códigos de caracteres de 8 bits se pueden interpretar de muchas maneras diferentes incluso en una sola computadora, dependiendo de la configuración: - y mucho menos las páginas de códigos que codifican para codificaciones de varios bytes. Entonces, en realidad es incluso peor de lo que aludiste en la última oración del segundo párrafo.
un CVn
@EuroMicelli esa es una muy buena información en realidad gracias por eso :)
JAVA
29

Pues podría .

Por ejemplo, en el dialecto de C utilizado en el sistema operativo del Plan 9main normalmente se declara como una voidfunción, pero el estado de salida se devuelve al entorno de llamada al pasar un puntero de cadena a la exits()función. La cadena vacía denota éxito, y cualquier cadena no vacía denota algún tipo de falla. Esto podría haberse implementado al maindevolver un char*resultado.

Y sin duda sería posible implementar un sistema con una floato doubleestado de salida.

¿Entonces por qué int? Es solo una cuestión de convención, y hay un gran valor para que los sistemas operativos y los programas que se ejecutan bajo ellos obedezcan una convención común.

La convención de Unix es usar un código de estado entero, con 0 que denota éxito y falla que no denota cero (porque típicamente solo hay una forma de tener éxito, pero múltiples formas de fallar). No sé si esa convención se originó con Unix; Sospecho que vino de sistemas operativos anteriores.

La coma flotante sería una convención más difícil, porque (a) el soporte de coma flotante no es universal, (b) es más difícil definir un mapeo entre los valores de coma flotante y las condiciones de error, (c) diferentes sistemas usan diferentes flotantes. representaciones de puntos, y (d) simplemente imagine la diversión de localizar un error de redondeo en el estado de salida de su programa. Los enteros, por otro lado, se prestan muy bien para enumerar códigos de error.

El Plan 9, como mencioné, usa cadenas, pero eso impone cierta complejidad para la administración de la memoria, la codificación de caracteres, etc. Era, hasta donde yo sé, una idea nueva cuando el Plan 9 lo implementó, y no reemplazó el existente. Convención generalizada.

(Por cierto, en C ++ solomain puede regresar , y en C está permitido solo si el compilador lo admite específicamente. Muchos compiladores no se quejan muy alto si escribe , pero es solo una ligera exageración decir que está mal ).intvoid mainvoid main

Keith Thompson
fuente
9

El valor devuelto por el método principal es un "código de salida". La aplicación que llama (normalmente bash) la usa para probar si el programa finalizó como se esperaba. Devolver un número entero es la forma más fácil de hacerlo en el nivel del sistema operativo. Double no tiene sentido para el código de error y una cadena es difícil de mantener en el nivel del sistema operativo (no hay GC).

xeranic
fuente
3
¿Por qué una cadena necesita ser recogida de basura mientras que un entero no?
Brad
44
@Brad, las cadenas tienen una longitud variable y serían, en esencia, lo mismo que devolver una matriz que podría ser un carácter o miles. La memoria dinámica sería una molestia, mientras que un int es un tamaño bastante fijo que no es tan difícil de manejar.
JB King
-4

main debe devolver el estado del programa que se ejecuta. Si se ejecuta con éxito (devuelve 0 que es EXIT_SUCCESS) o no (devuelve 1 significa EXIT_FAILURE) cualquier número distinto de cero transmite el mismo significado pero cero indica que no hay errores o ejecución exitosa.

dileepkumar p
fuente
1
Esto no parece ofrecer nada sustancial sobre los puntos planteados (y mucho mejor explicados) en las respuestas anteriores que se publicaron hace varios años
mosquito