I know that in computers, value returned by the
main() function is received by the operating system.
But, what happens in the
main() function of a microcontroller?
On a microcontroller,
main() is not really expected to ever exit, and the behavior if it does is not defined — so it's up to whoever wrote the C runtime for the microcontroller. I've seen systems that:
- Have an implicit loop around
main(), so that if it exits, it simply gets called again.
- Have a simple "jump-to-self" loop that gets executed if
- Simply execute the rest of code memory that follows the call to
main(). This is called "running off into the weeds".
I've never seen one that actually does anything at all with the value returned by
main(). If this is something you actually care about, then you should take a look at — and possibly modify — the source code for your system's C runtime library.
A common misunderstanding/myth is that
int main is the only valid form specified by the standard. That is not true.
The C standard speaks of two implementations: hosted and freestanding. "Implementation" in this case means compiler. Hosted compilers compile for a specific OS and freestanding compilers compile for a specific bare metal application. Embedded systems are almost always freestanding systems - even in the case of RTOS.
Freestanding implementations may use any form for
main(), they don't even need to have a function called main. Most often, they use the form
void main (void), since it doesn't make any sense to return anything.
What's important to realize here is that it is always the compiler that decides the form of
main() and never the programmer.
Freestanding implementations that do return something from
main() are very questionable. Makes you wonder if the people who made the compiler actually read the standard...
The C language standard allows for the implementation defined variation
void main( void ) and this is the usual form in embedded systems - simply because they are not expected to return.
If you look at the compiler setup, there is usually a bootstrap snippet of code, called from the reset vector, which performs some basic initialisation (including eg coping of initialisation values into variables) before calling main().
This will also (usually) be within an infinite loop, or perhaps perform a reset, if
It (as other answers mentioned) depends on your toolchain, but for example in GCC
main is compiled as other functions, so its return value will be stored accordingly to calling conventions (on ARM I am using right not with GCC it will be put to R0 just before return).
I guess that is is simillar on AVR-GCC, so custom script can use this value after main returns.