web-dev-qa-db-fra.com

Pourquoi «main» ne peut-il pas retourner un double ou une chaîne plutôt que int ou void?

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

Je sais un peu que nous ne pouvons pas faire cela parce que main est appelé par la bibliothèque d'exécution et il attend une syntaxe comme int main() ou int main(int,char**) donc nous devons nous en tenir pour que.

Donc ma question est: pourquoi main a-t-il la signature de type qu'il a, et pas une autre?

38
JAVA

La valeur de retour de main doit ê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 terminé avec succès ou y a-t-il eu une erreur?"

S'il s'agit d'une chaîne, la réponse devient difficile dans différentes langues. Les internes d'une chaîne Pascal (le premier octet est la longueur) et d'une chaîne FORTRAN (fixe, complétée à une certaine 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 a été résolu, que feriez-vous pour répondre à la question que le SE avait du programme? Les comparaisons de chaînes sont lourdes d'erreurs ("succès" vs "succès"), et bien que l'erreur puisse être plus utile à un humain, elle est plus difficile à gérer pour le système d'exploitation ou un autre programme (Shell). Il y avait également des différences significatives, même dans les chaînes elles-mêmes - EBCDIC (avec toutes ses pages de codes) par rapport à ASCII.

Les flottants et les doubles ne fournissent aucune valeur supplémentaire par rapport à l'entier pour communiquer les données en retour au système d'exploitation (et au shell). Pour la plupart, aucune de ces parties de l'ordinateur ne traite des 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 avez choisi une valeur particulière pour réussir). Encore une fois, les virgules flottantes ne sont pas cohérentes - un flottant sur une machine 8 bits était différent du flotteur sur une machine 16 bits et 32 ​​bits (et ce ne sont que les "normaux" - même dans IBM, la virgule flottante n'était pas normalisée entre machines du même constructeur jusque dans les années 80). Et puis vous avez des ordinateurs décimaux vs binaires. Les valeurs à virgule flottante ne sont pas cohérentes et ne fournissent pas de données significatives.

Cela nous laisse vraiment avec l'octet et l'entier comme options. La convention qui a été établie était "0" était un succès, et tout le reste é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, signifie DEF, etc.) ou utilisé comme drapeaux (0x0001 signifie que cela a échoué, 0x0002 signifie que cela a échoué, 0x0003 signifie ceci et cela a échoué). Limiter cela à un seul octet pourrait facilement manquer de drapeaux (seulement 8), donc la décision a probablement été d'utiliser un entier.

88
user40980

Eh bien, cela pourrait .

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

Et il serait certainement possible d'implémenter un système avec un état de sortie float ou double.

Alors pourquoi int? C'est juste une question de convention - et il y a une valeur énorme à ce que les systèmes d'exploitation et les programmes qui s'exécutent sous eux obéissent à une convention commune.

La convention Unix consiste à utiliser un code d'état entier, 0 indiquant le succès et l'échec non nul (car il n'y a 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 pour origine Unix; Je soupçonne que cela provenait de systèmes d'exploitation antérieurs.

La virgule flottante serait une convention plus difficile, car (a) la prise en charge des virgules flottantes n'est pas universelle, (b) il est plus difficile de définir une correspondance entre les valeurs à virgule flottante et les conditions d'erreur, (c) différents systèmes utilisent des flottants différents - des représentations ponctuelles et (d) imaginez le plaisir de retrouver une erreur d'arrondi dans l'état de sortie de votre programme. Les entiers, en revanche, se prêtent très bien à l'énumération des codes d'erreur.

Le plan 9, comme je l'ai mentionné, utilise des chaînes, mais cela impose une certaine complexité pour la gestion de la mémoire, le codage des caractères, etc. Pour autant que je sache, c'était une nouvelle idée lorsque le plan 9 l'a mis en œuvre, et il n'a pas remplacé l'existant. convention largement répandue.

(Par ailleurs, en C++ main peut uniquement retourner int, et en C void main n'est autorisé que si le compilateur le prend spécifiquement en charge. 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 .)

29
Keith Thompson

La valeur renvoyée par la méthode principale est un "code de sortie". Il est utilisé par l'application appelante (normalement bash) pour tester 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).

9
xeranic