Pourquoi ne peut pas `main` retourner un double ou une chaîne plutôt que int ou void?

38

Dans de nombreux langages tels que C, C ++ et Java, la mainméthode / fonction a un type de retour de voidou int, mais pas doubleou String. Quelles pourraient être les raisons derrière cela?

Je connais un peu que nous ne pouvons pas le faire parce que l' mainon appelle par la bibliothèque d'exécution et il attend à une syntaxe comme int main()ou int main(int,char**)si nous devons nous en tenir à cela.

Ma question est donc la suivante: pourquoi mainune signature de type at-elle été utilisée et non une signature différente?

JAVA
la source
19
Que serait une double valeur de retour signifie ? Quelle valeur de retour de chaîne ne signifie ?
1
Je comprends que cela ne veut rien dire. Mais d’autres raisons et conventions?
JAVA
1
Je pense que cela ne veut rien dire, simplement parce que, universellement, il a été choisi 0 pour une sortie normale et un non nul pour un anormal.Un int a été choisi comme type de données le plus simple avec une compatibilité multilingue étendue. @ delnan
JAVA
@sunny D'après mon expérience des systèmes d'exploitation de type Unix, 0 est utilisé comme une "sortie normale" (0 erreur) car il est dépourvu d'ambiguïté par rapport à d'autres valeurs entières. Étant donné que la plupart des langues modernes (pas toutes) sont conçues pour être similaires à (si elles ne sont pas conçues au verso), et que C était utilisé pour écrire Unix, je dirais que c'était une décision historique de KnR.
Jamie Taylor
3
@sunny "compatibilité large entre les langues" n'était pas un problème. C et UNIX ont été écrits en tandem. La raison pour laquelle de nombreuses autres langues retournent ints est qu’elles ont été conçues pour fonctionner dans des environnements UNIX ou de type UNIX.

Réponses:

88

La valeur de retour de maindoit être transmise au système d'exploitation ( tout système d'exploitation) d'une manière unique et cohérente. Les informations que le système d'exploitation doit connaître sont "le programme s'est-il arrêté correctement ou y a-t-il une erreur?"

S'il s'agit d'une chaîne, la réponse devient difficile dans différentes langues. Les éléments internes d'une chaîne Pascal (le premier octet est de longueur) et d'une chaîne FORTRAN (fixée, complétée à une valeur) et d'une chaîne C (terminée par un caractère nul) sont tous différents. Cela rendrait difficile le retour d'une valeur cohérente au système d'exploitation. En supposant que cela soit résolu, que feriez-vous pour répondre à la question du système sur le système d'exploitation? Les comparaisons de chaînes sont entachées d'erreurs ("succès" ou "succès"), et si l'erreur peut être plus utile pour un humain, elle est plus difficile à gérer pour le système d'exploitation ou un autre programme (shell). Il y avait aussi des différences significatives, même dans les chaînes elles-mêmes - EBCDIC (avec toutes ses pages de code) par rapport à ASCII.

Les flottants et les doubles ne fournissent aucune valeur supplémentaire sur l'entier pour la communication de données en retour au système d'exploitation (et au shell). Pour la plupart, aucune de ces parties de l'ordinateur ne traite de nombres à virgule flottante. Les doubles ne sont pas non plus énumérables, ce qui rend les comparaisons difficiles. N'étant pas énumérables, ils rendent compte de l'erreur (en supposant que vous ayez choisi une valeur particulière pour réussir). Encore une fois, les points flottants ne sont pas cohérents - un float sur une machine 8 bits était différent de celui des machines 16 bits et 32 ​​bits (et ce ne sont que des machines «normales» - même au sein d'IBM, la virgule flottante n'était pas normalisée. entre les machines du même fabricant jusqu’aux années 1980). Et puis vous avez des ordinateurs décimaux contre des ordinateurs binaires. Les valeurs en virgule flottante ne sont pas cohérentes et ne fournissent pas de données significatives.

Cela nous laisse vraiment avec les octets et les nombres entiers comme options. La convention qui a été établie était «0» était un succès, et toute autre chose était une erreur. Un entier donne plus de place qu'un octet pour signaler l'erreur. Il peut être énuméré (retour de 1 signifie XYZ, retour de 2 signifie ABC, retour de 3, DEF, etc.) ou utilisé en tant qu'indicateur ( 0x0001signifie que cet échec a 0x0002signifié que 0x0003cela a échoué. Limiter cela à un seul octet pourrait facilement manquer de drapeaux (seulement 8), la décision était donc probablement d'utiliser un entier.

Sean Allred
la source
2
Je pense que main est appelé par la bibliothèque d'exécution c / c ++ avant de l'appeler, qui est également un morceau de code chargé avec notre code et appelé par l'os @ MichaelT
JAVA
5
main()est appelé de différentes manières sur différents systèmes d'exploitation. En C, comment la méthode main () est-elle initialement appelée? va dans cela.
25
Je pense que le point clé à comprendre est que main- contrairement aux autres fonctions de tout programme - ne fait pas partie d'un protocole défini par le programmeur, mais du protocole utilisé pour assurer l'interface avec l'hôte (OS). Vous ne pouvez pas le choisir parce que vous ne l'avez jamais choisi. À un niveau plus pragmatique, UNIX s'attend à ce qu'un int soit renvoyé par un processus. Le protocole C-to-UNIX fait exactement cela. Un argument analogue peut être utilisé pour le passage d’arguments: si C avait été inventé pour un système d’exploitation / hôte qui ne passait que des nombres comme arguments (par exemple, aucune ligne de commande), les arguments seraient des entiers au lieu de chaînes.
Euro Micelli
2
IBM a adopté le concept de pages de code d’EBCDIC sur ses PC. Ils nous hantent encore aujourd’hui, 35 ans après l’introduction de l’IBM 5150. La norme ASCII 7 bits n’a pas de pages de code, mais les codes de caractères 8 bits peuvent être interprétés de différentes manières, même sur un seul ordinateur, en fonction des paramètres - - sans parler des pages de code qui codent pour des codages sur plusieurs octets. C'est donc pire que ce à quoi vous faites allusion dans la dernière phrase du deuxième paragraphe.
un CVn
@EuroMicelli, c'est une très bonne information, merci pour cela :)
JAVA
29

Eh bien, ça pourrait .

Par exemple, dans le dialecte de C utilisé dans le système d’exploitation Plan 9 , il mainest normalement déclaré en tant que voidfonction, mais l’état de sortie est renvoyé à l’environnement appelant en transmettant un pointeur de chaîne à la exits()fonction. La chaîne vide indique un succès et toute chaîne non vide indique un type d'échec. Cela aurait pu être implémenté en mainrenvoyant un char*résultat.

Et il serait certainement possible de mettre en place un système avec un statut floatou un doublestatut de sortie.

Alors pourquoi int? C'est juste une question de convention - et il est extrêmement précieux de faire en sorte que les systèmes d'exploitation et les programmes qui y sont exécutés obéissent à une convention commune.

La convention Unix consiste à utiliser un code d’état entier, 0 indiquant la réussite et non nul indiquant l’échec (car il n’ya généralement qu’une seule façon de réussir, mais plusieurs façons d’échouer). Je ne sais pas si cette convention a son origine avec Unix; Je soupçonne que cela provient de systèmes d'exploitation antérieurs.

La convention en virgule flottante serait une convention plus difficile, car (a) la prise en charge de la virgule flottante n’est pas universelle, (b) il est plus difficile de définir un mappage entre les valeurs en virgule flottante et les conditions d’erreur, (c) différents systèmes utilisent différentes méthodes de calcul. (d) imaginez simplement le plaisir de détecter une erreur d’arrondi dans le statut de sortie de votre programme. Les entiers, par contre, se prêtent très bien à l'énumération des codes d'erreur.

Plan 9, comme je l'ai mentionné, utilise des chaînes, mais cela impose une certaine complexité pour la gestion de la mémoire, l'encodage des caractères, etc. Il s'agissait, pour autant que je sache, d'une nouvelle idée lorsque Plan 9 l'a mise en œuvre, et cela ne remplace pas l'existant. convention répandue.

(Incidemment, le C ++ mainne peut que revenir int, et le C void mainn'est autorisé que si le compilateur le supporte spécifiquement. De nombreux compilateurs ne se plaignent pas très fort si vous écrivez void main, mais ce n'est qu'une légère exagération de dire que c'est faux .)

Keith Thompson
la source
9

La valeur renvoyée par la méthode principale est un "code de sortie". Il est utilisé par l’appelant appelant (normalement bash) pour vérifier si le programme s’est terminé comme prévu. Renvoyer un entier est le moyen le plus simple de le faire au niveau du système d'exploitation. Double n'a aucun sens pour le code d'erreur et une chaîne est difficile à maintenir au niveau du système d'exploitation (il n'y a pas de GC).

xéranique
la source
3
Pourquoi une chaîne doit-elle être nettoyée alors qu'un entier n'est pas?
Brad le
4
@ Brad, les chaînes ont une longueur variable, ce qui revient au même que renvoyer un tableau qui pourrait être un caractère ou des milliers. La mémoire dynamique serait une douleur alors qu'un int est une taille plutôt fixe qui n'est pas si difficile à gérer.
JB King
-4

main doit renvoyer l’état du programme qui est exécuté. Que celui-ci soit exécuté avec succès (0, EXIT_SUCCESS) ou non (1 signifie EXIT_FAILURE). Un nombre autre que zéro transmet le même sens, mais zéro n’indique aucune erreur ni exécution réussie.

dileepkumar p
la source
1
cela ne semble offrir aucun avantage substantiel par rapport aux points soulevés (et bien mieux expliqués) dans les réponses précédentes postées il y a plusieurs années
Gnat