Qui reçoit la valeur renvoyée par main ()?

34

Je sais que dans les ordinateurs, la valeur renvoyée par la main()fonction est reçue par le système d'exploitation. Mais que se passe-t-il dans la main()fonction d'un microcontrôleur?

utilisateur18118
la source
7
J'utilise toujours void main () lorsque j'utilise C pour les microcontrôleurs PIC. Lorsque vous utilisez des compilateurs C pour les microcontrôleurs, cela n’a vraiment aucune importance. Parce qu'il n'y a pas de système d'exploitation qui exécute le (par exemple) "main.c". S'il y a quelque chose comme un RTOS en cours d'exécution dans ce microcontrôleur, le système d'exploitation est alors le "main.c".
Abdullah Kahraman
4
Pas vraiment un duplicata, mais au moins lié: electronics.stackexchange.com/q/30830/4950
PetPaulsen
1
Comment la fonction de démarrage est définie n'est généralement pas à vous de décider. L'environnement que vous utilisez documentera les formulaires de fonction de démarrage pris en charge. Les implémentations C hébergées doivent prendre en charge deux formes mainavec deux signatures différentes, qui retournent toutes les deux int. Si vous utilisez une implémentation C autonome, cette implémentation dicte la manière dont vous devez écrire la fonction de démarrage. Vous ne pouvez pas écrire une voidfonction de retour simplement parce qu'elle ne retourne pas. Le comportement de non-retour est différent du type de fonction qui influence les conventions d'appel globales.
Kaz

Réponses:

42

Sur un microcontrôleur, main()on ne s'attend pas vraiment à ce qu'il se ferme, et le comportement s'il n'est pas défini n'est pas défini - par conséquent, c'est à quiconque a écrit le runtime C pour le microcontrôleur. J'ai vu des systèmes qui:

  • Utilisez une boucle implicite main()pour que, si elle se ferme, elle soit simplement appelée à nouveau.
  • Ayez une simple boucle "saute-à-soi" qui est exécutée si main()jamais se termine.
  • Il suffit d’exécuter le reste de la mémoire de code qui suit l’appel à main() . C'est ce qu'on appelle "couler dans les mauvaises herbes".

Je n'en ai jamais vu qui fasse quoi que ce soit avec la valeur renvoyée par main(). Si cela vous tient à cœur, vous devriez jeter un coup d'œil - et éventuellement modifier - le code source de la bibliothèque d'exécution C de votre système.

Dave Tweed
la source
1
Tu m'as battu à ça. +1 pour la synchronicité.
Adam Lawrence
9
La norme C définissant main()une intvaleur de retour n'a évidemment pas été conçue avec un microcontrôleur sans système d'exploitation. Il s’agit donc d’un comportement non spécifié et tout peut arriver en fonction de votre exécution C, comme le mentionne Dave.
Ndim
4
C en cours d' exécution sur un microcontrôleur OS-moins pourrait être considéré comme une mise en œuvre pose libre, et la norme C ne nécessite même pas un environent autoportant pour avoir une main(), beaucoup moins définir sa valeur de retour. Cela dépend de l'implémenteur.
KutuluMike
2
@ndim - pour diviser les cheveux, void main( void )est un comportement défini par l'implémentation , pas un comportement non spécifié .
Andrew
1
@ MichaelEdenfield: En effet. Cependant, tout le code en C est défini en termes de fonctions, il n’est donc jamais possible d’avoir un système récemment mis à jour entièrement écrit en C; il doit y avoir au moins un tout petit langage d'assemblage (ou autre) qui configure un environnement minimal pour pouvoir appeler une fonction C. Le nom le plus évident pour cette fonction est main().
Dave Tweed
5

Un mythe commun / mythe est que int mainc'est la seule forme valide spécifiée par la norme. Ce n'est pas vrai.

La norme C parle de deux implémentations: hébergée et autonome. "Implémentation" dans ce cas signifie compilateur. Les compilateurs hébergés compilent pour un système d'exploitation spécifique et les compilateurs autonomes compilent pour une application nu-metal spécifique. Les systèmes embarqués sont presque toujours des systèmes autonomes, même dans le cas du RTOS.

Les implémentations autonomes peuvent utiliser n’importe quelle forme main(), elles n’ont même pas besoin d’une fonction appelée main. Le plus souvent, ils utilisent le formulaire void main (void), car cela n'a aucun sens de renvoyer quoi que ce soit.

Ce qui est important à comprendre, c’est que c’est toujours le compilateur qui décide de la forme main()et non le programmeur.

Implémentations autoportant qui font quelque chose de retour main()sont très contestables. On se demande si les personnes qui ont créé le compilateur lisent réellement le standard ...

Détails ici .

Lundin
la source
3

La norme de langage C autorise la variante définie par la mise en œuvre. void main( void )Il s'agit de la forme habituelle dans les systèmes embarqués, simplement parce qu'ils ne sont pas censés être renvoyés.

Si vous regardez la configuration du compilateur, il y a généralement un fragment de code d'amorçage, appelé à partir du vecteur de réinitialisation, qui effectue une initialisation de base (y compris par exemple l'adaptation des valeurs d'initialisation à des variables) avant d'appeler main ().

Ce sera également (généralement) dans une boucle infinie, ou peut-être effectuer une réinitialisation, si main()renvoie

Andrew
la source
0

Cela (comme d'autres réponses mentionnées) dépend de votre chaîne d'outils, mais par exemple dans GCC mainest compilé comme d'autres fonctions, sa valeur de retour sera stockée conformément aux conventions d'appel (sur ARM, je n'utilise pas correctement avec GCC, il sera mis à R0 juste avant le retour).

Je suppose que c'est la même chose sur AVR-GCC, donc un script personnalisé peut utiliser cette valeur après les retours principaux.

Kwesolowski
la source
cela manque le point
Chris Stratton
Il souligne que celui qui appelle mainpeut obtenir sa valeur de retour. Bien sûr, il est ignoré dans 99,9% des cas, mais answer fournit des informations sur qui peut recevoir cette valeur de retour.
Kwesolowski