EAX Register - Page 1
Forum section: electronics / general

author: BitsnBytes
author_rank: Contributor
timestamp: February 09, 2021, 04:20:43 pm
content: Hello,EAX Register is used to store the return value. Is there any such register in microcontrollers which holds the value returned bymain().

author: grumpydoc
author_rank: Super Contributor
timestamp: February 09, 2021, 04:27:26 pm
content: Quote from: BitsnBytes on February 09, 2021, 04:20:43 pmThat's a big assumption.QuoteDepends on the calling convention of the compiler and architecture that you are using.

author: ataradov
author_rank: Super Contributor
timestamp: February 09, 2021, 04:29:37 pm
content: On ARM according to the EABI calling conventions, return values less than 32 bits in size are stored in R0.And it is different for different calling conventions and architectures.

author: BitsnBytes
author_rank: Contributor
timestamp: February 09, 2021, 04:50:04 pm
content: QuoteSo can we use the return value to do something?I am talking about microcontrollers

author: grumpydoc
author_rank: Super Contributor
timestamp: February 09, 2021, 05:02:28 pm
content: Quote from: BitsnBytes on February 09, 2021, 04:50:04 pmThe problem is that you haven't constrained your question enough to be able to offer a useful answer."Microcontrollers" covers everything from 8 bit PIC upwards, and at the top end gets blurred between Microcontroller, SOC and desktop architectures.Yes, the return value from main() (which is an int) will probably go in a register, but it does not *have* to, there doesn't even have to be a main() if you are coding in assembler on a platform - or a language other than C/C++What specific architecture & compiler are you using?

author: hli
author_rank: Frequent Contributor
timestamp: February 09, 2021, 05:02:34 pm
content: Quote from: BitsnBytes on February 09, 2021, 04:20:43 pmmain()does not return. Or rather, when it does, your controller either crashes or reboots (most likely the former). To be more exact,mainis just address where the program gets started (after the startup code did run).

author: grumpydoc
author_rank: Super Contributor
timestamp: February 09, 2021, 05:04:09 pm
content: Quote from: hli on February 09, 2021, 05:02:34 pmYes, but main() is defined in the C standard to return an int, so it *is* meaningful to talk about that return value, even if main() returning is not always a terribly good thing to do.

author: ataradov
author_rank: Super Contributor
timestamp: February 09, 2021, 05:11:02 pm
content: In the embedded systems main() typically return nowhere. Or in the best case to while (1); loop.What do you want to do with that value.And also, yes, you have not specified your MCU.

author: BitsnBytes
author_rank: Contributor
timestamp: February 09, 2021, 05:14:15 pm
content: I am working on ATMEGA328P.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 09, 2021, 05:18:05 pm
content: And compiler? GCC?https://gcc.gnu.org/wiki/avr-gccint is 16 bits so the result will be in r25:r26.Tim

author: ataradov
author_rank: Super Contributor
timestamp: February 09, 2021, 05:24:26 pm
content: GCC startup code calls main() and then jumps to "exit". "exit" can't return. But you can declare your own version and look at those registers and do whatever you want.

author: woofy
author_rank: Frequent Contributor
timestamp: February 09, 2021, 05:25:15 pm
content: The return value from main() is intended to return execution status to OS's such as *nix.It is meaningless in microcontrollers like the AVR, which should not return.Put your code in an endless loop:Code:while(1) {}

author: BitsnBytes
author_rank: Contributor
timestamp: February 09, 2021, 06:23:48 pm
content: Yeah actually I knew that return is meaningless in microcontroller, but I thought may be I don't know and there is a way to use a return value in microcontrollers.Thank you all for replies. I always learn from you guys!

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 09, 2021, 06:49:22 pm
content: I mean, there's nothing wrong with recursively calling main(args) -- but that particular approach is typically an anti-pattern reserved for thebest winnersworst offenders of theIOCCC, and on PC at that, rarely if ever something you'd have enough RAM to do on an MCU.So, the most common pattern on MCUs is for init to call main, and main to never return; and the compiler may still emit exit (typically an infinite loop), or the return and exit code can be disabled with an option.Tim

author: Siwastaja
author_rank: Super Contributor
timestamp: February 09, 2021, 06:51:40 pm
content: They are just general-purpose registers, nothing special on CPU.For inter-operation of pre-compiled parts (like libraries), it's a very good idea to follow a commonconvention, though.Often there is just one widely used convention for each architecture. Sometimes the gcc binary name gives hints which conventions it follows. For example, gcc-arm-none-eabi gives a few hints for you - like that binaries compiled by it follow the EABI conventions. (EABI being just a name for a set of standardized conventions; no one forces you to follow them but it's often a pretty good idea).My embedded projects define void main(), not int main(), for obvious reasons. Not a single person or tool has complained to me about that (yet). It may be a good idea to add noreturn attribute to main() - I remember avr-gcc generating a lot of excess push/pop code around main() eating up considerable amount of program memory in some of their smallest devices. Adding noreturn attribute lets the compiler do code size and possibly performance optimizations. while(1) loop wasn't enough for avr-gcc to deduce this behavior at least back when I needed to add noreturn.

author: hli
author_rank: Frequent Contributor
timestamp: February 10, 2021, 01:59:56 pm
content: Quote from: grumpydoc on February 09, 2021, 05:04:09 pmC0x:http://c0x.coding-guidelines.com/5.1.2.2.1.html162 The function called at program startup is named main.163 The implementation declares no prototype for this function.164 It shall be defined with a return type of int and with no parameters:int main(void) { /* ... */ }165 or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):int main(int argc, char *argv[]) { /* ... */ }166 or equivalent;167 or in some other implementation-defined manner.So the entry point must be namedmain, and accepting and returning parameters is optional.void main(void)should be legal then.If you want to go deeper into that rabbit hole -maindoes not need to be a function:https://jroweboy.github.io/c/asm/2015/01/26/when-is-main-not-a-function.html

author: newbrain
author_rank: Super Contributor
timestamp: February 10, 2021, 02:53:44 pm
content: Quote from: hli on February 10, 2021, 01:59:56 pmThe only authority here is the standard.To put it very briefly:In a hosted environment the only standard-defined return type for main() is int, and the name is main (duh).There are exactly two signatures allowed,int main(void)andint main(int, char**)or their equivalent.It allowable, though, for an implementation to define additional signatures, this, as all implementation-defined behaviour,mustbe documented.main is also special in that, while returning an int, does not need an explicit return statement, falling off the closing } returns 0.In a freestanding environment, the name and signature of the function invoked at startup is completely implementation-defined.In this case (where I would put most MCU environments) a void main() - or any other function name and signature,as described by the documentation- is acceptableThe relevant sections of the C11 standard (no changes AFAICR from C89, C99 and in C18) are:5.1.2.1 Freestanding environment5.1.2.2 Hosted environment5.1.2.2.3 Program terminationJ.1 Unspecified behavior (2nd paragraph)J.2 Undefined behavior (4th paragraph)J.3.2 Environment (4th and 5th paragraphs)All in all, void main() is then only acceptable as an alternative, implementation-definedand documentedsignature.That said, after being traumatized in my infancy by the exposure to Schildt's books, seeing void main() still makes my skin crawl

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 10, 2021, 03:14:12 pm
content: Yes, I'd even suggest NOT using the 'main' identifier on freestanding environments if you're not going to follow the standard (eg., not returning a value from main.)That said, "int main(void)" is not harder to write than "void main(void)". To avoid warnings, you then have to return a value. But how hard is it to add "return 0;" at the end of the function. There, you comply with the standard, you get no warning, and everyone is happy.On MCUs, there commonly is some startup code (usually written in assembly) doing some very low-level init. stuff and then calling main(). The startup code also usually ignores the return value, and then goes into an infinite loop. Now some particular environments may do it differently; sometimes, on very simple targets, the main() function may directly be the entry point, in which case, if the main() function ever returns, the target will usually "crash" (so in this case, never returning, putting an infinite loop at the end of main(), is a good idea.) On some other particular environments, the return value of main() may actually be used.

author: newbrain
author_rank: Super Contributor
timestamp: February 10, 2021, 03:38:26 pm
content: Quote from: SiliconWizard on February 10, 2021, 03:14:12 pmNot since a long time, with reasonable compilers:Code:$cat noret.cint main(void){}int f(void){}$gcc -std=c11 -Wall -Wextra -pedantic -c noret.cnoret.c: In function ‘f’:noret.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]}^$clang -std=c11 -Weverything -pedantic -c noret.cnoret.c:6:5: warning: no previous prototype for function 'f' [-Wmissing-prototypes]int f(void)^noret.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]}^2 warnings generated.$EtA: Also Microsoft C++ compiler agrees:Code:C:\Users\git>cl /Wall noret.cMicrosoft (R) C/C++ Optimizing Compiler Version 19.16.27027.1 for x86Copyright (C) Microsoft Corporation. All rights reserved.noret.cc:\users\git\noret.c(7) : warning C4716: 'f': must return a valueMicrosoft (R) Incremental Linker Version 14.16.27027.1Copyright (C) Microsoft Corporation. All rights reserved./out:noret.exenoret.obj

author: BitsnBytes
author_rank: Contributor
timestamp: February 10, 2021, 03:49:15 pm
content: QuoteAVR-GCC

author: ejeffrey
author_rank: Super Contributor
timestamp: February 10, 2021, 04:10:40 pm
content: Microcontrollers generally use freestanding rather than hosted C so they are allowed to do whatever they want.However, void main(void) has never been standard C. The two standard prototypes in the section quotes above both return int. Generally this will not be a big deal. You might get a garbage return value but gcc will actually often zero the return value for you. A platform can have other platform specific entrypoints but depending on how you parse that quote perhaps they should all return int.However in standard C main is not required to be a normal function at all. Calling it recursively for instance is undefined. This is because the main function might get renamed to match a platform specific entrypoint like _start. It might also have a non standard prologue and epilog or use a different calling convention on some platforms. All modern C runtimes that I know of have a function like _libc_init that calls main as a normal function but that is not required.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 10, 2021, 08:47:55 pm
content: Quote from: newbrain on February 10, 2021, 03:38:26 pmThis is actually not a matter of being "reasonable", but merely being (at least) C99-compliant.That's mentioned in the C99 standard: "reaching the } that terminates the main function returns a value of 0."If you compile the code with '-std=c89', you'll get a warning for main(). So, it all depends on which standard you're complying with. And I don't know if avr-gcc, for instance, is C99-compliant (maybe it is, I just have never used it.)I find that exception a bit peculiar anyway. Defining a function that returns a value but never returns anything explicitely? It's odd. The decision of the committee here is questionable IMO. Why disallow 'void main(void)' and allow it not to return any value, this is bizarre. But this is just so.

author: ejeffrey
author_rank: Super Contributor
timestamp: February 11, 2021, 02:21:37 am
content: The return type of main is int because the exit status is not optional. It defaults to zero because that means no error.Sure the standard could have said that void main will act as if it returned zero but it makes more sense to me to have the return type int and defaults to zero if it reaches the end.

author: westfw
author_rank: Super Contributor
timestamp: February 11, 2021, 02:30:12 am
content: Quotecorrect link; wrong answer...QuoteNote that there are several compilers for AVR that have significantly different calling conventions (that use separate stacks for data and control paths, for example.)Using "register 0" is very popular in general, but on AVR A0-A15 are sort-of "2nd class registers." I'm not sure how they came up with R24.

author: JohnnyMalaria
author_rank: Super Contributor
timestamp: February 11, 2021, 02:42:53 am
content: According to my copy of The C Programming Language (Kernighan and Ritchie, 2nd ed), it's neitherint main()orvoid main()but justmain(). It also says:QuoteLater,Quote

author: ejeffrey
author_rank: Super Contributor
timestamp: February 11, 2021, 02:55:52 am
content: int main() and main() are the same thing. In C the return type is int by defailt if it isn't specified. Not just for main but for all functions.

author: BitsnBytes
author_rank: Contributor
timestamp: February 11, 2021, 07:27:28 pm
content: QuoteYeah you are right, but the compilers needs the data type to be explicitly written to main() for successful compilation. int with main() only has this role and no other role in microcontrollers!

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 11, 2021, 08:35:35 pm
content: Quote from: BitsnBytes on February 11, 2021, 07:27:28 pmWhat I think ejeffrey means here is that defining the function as simply 'main()' is equivalent to 'int main(void)'. And... they probably implied by that that it saves a few keystrokes and having to care about the return value.But... default return types for function definitions is not part of the C standard anymore (since C99). There is no mention of that in C99 and later standards. It was allowed in C89.Most compilers supporting C99 or later will accept this but will give you a warning.This is deprecated and should IMO not be used.

author: ejeffrey
author_rank: Super Contributor
timestamp: February 12, 2021, 02:54:02 am
content: Yeah I was just replying to this:Quote from: JohnnyMalaria on February 11, 2021, 02:42:53 amNot recommending that you make a habit of using implicit int return types. I didn't realize that it was dropped from C99, but would not recommend it in any case.

author: BitsnBytes
author_rank: Contributor
timestamp: February 12, 2021, 04:30:52 pm
content: QuoteAhhhh!I was using _Bool, it was working in one computer and not working on my colleague computer.Now I realized that may be his compiler is not C99 supported because _Bool is introduced in C99.I was reading your post and it clicked in my mind

author: Siwastaja
author_rank: Super Contributor
timestamp: February 12, 2021, 05:28:46 pm
content: Make sure they look at the compiler help/documentation if they need to enable C99 support by some compiler flag; for example, in gcc, -std=c99.If their compilerreallydoes not support c99, I think that's a good reason to upgrade, that thing is over 20 years old now. Or is it some very exotic architecture?Also, IMHO,_Boolis a stupid and inconvenient name, only picked to avoid clashes in old code bases. The idea is to include <stdbool.h> and usebool; do it if you can (i.e., you are writing new code, or your old code does not usebool,trueorfalseas variable or type names).

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 12, 2021, 07:59:21 pm
content: Quote from: Siwastaja on February 12, 2021, 05:28:46 pmYes, although gcc's default (so not needing explicit -std=c99) has been C99 for a long time now, so you shouldn't need to add the option... except for actually "downgrading" to C99, because the recent gcc versions have C11 as default. And by recent... it's actually been since version 6.x I believe (and we're at 10.x!), or maybe even 5.x?To be accurate, the default now is actually not exactly C11, but a gnu-dialect of C11 (it adds specific gcc features on top of C11). An explicit "-std" option should restrict support to plain C standard, although I know some non-standard features are still supported with -std=cxx. For instance, attributes. I don't think they are part of the standard? (I may have missed that though.)But unless you're using a very old gcc version, or you're willing to be very pedantic language-wise, you can safely use any C99 feature without explicitely setting the '-std' option.Quote from: Siwastaja on February 12, 2021, 05:28:46 pmYeah. Absolutely. As you said, that was to avoid potential identifier clashes - especially since "bool" was actually a very popular identifier in old code bases. So, that may look ugly, but it's certainly not stupid.But yes, you should prefer the standard headers and not directly use the underscore-prefixed identifiers if you can avoid them.

author: BitsnBytes
author_rank: Contributor
timestamp: February 12, 2021, 08:45:28 pm
content: QuoteAlright! thanks

author: BitsnBytes
author_rank: Contributor
timestamp: February 12, 2021, 08:50:46 pm
content: QuoteYeah you are right and I was using MACROS for true and false using #defineI should have used stdbool.hPlease clarify _Bool is a specifier or identifier?Regards

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 12, 2021, 09:09:55 pm
content: Quote from: BitsnBytes on February 12, 2021, 08:50:46 pmNot that it really matters, but _Bool is listed in the standard as a "type specifier" (along with void, char, int, etc.)Identifiers are "user-defined", so what matters here is that you can consider _Bool as a keyword of the C language starting with C99. That means it's part of the core language, and is not itself defined in some header, or something.As such, it has a specific behavior. It's not like an 'int'. Assignments to a _Bool variable can only result in '0' or '1' values. Its actual "size" is implementation-defined though. So it depends. You shouldn't rely on it. You can use sizeof() to see how big it is on your specific platform.This '0' and '1' specificity is trickier than it looks, although in most cases you shouldn't make that matter. Let's see:bool b = 10; // b will actually contain '1' after this assignmentBUT, as the _Bool type may actually hold a much larger range of values from a low-level point of view, it could contain something else that 0 or 1 if you use pointers to one and alias it with a different type. Don't mess with _Bool!stdbool.h, OTOH, is just a thin (but standard) layer on top of it. It usually defines 'bool' either with a macro such as:#define bool _Boolor with a typedef:typedef _Bool bool;and additionally defines 'true' and 'false'.

author: BitsnBytes
author_rank: Contributor
timestamp: February 13, 2021, 08:22:24 am
content: QuoteIt is of 8 bits. Yeah I have started using standard library stdbool.hRegards

author: ejeffrey
author_rank: Super Contributor
timestamp: February 13, 2021, 04:07:27 pm
content: Quote from: SiliconWizard on February 12, 2021, 07:59:21 pmThe -std= option makes gcc standards compliant which means it disables extensions that conflict with the standard, I.e. those that would break a standards compliant program. Double underscore words like attributes are reserved by the standard for implementations so they are still allowed. In some cases gnu extensions can be spelled with and without underscores and the std=cxx option disables only the version without underscores.