C programming loop question main() vs. while(1)

Thread Starter

ke5nnt

Joined Mar 1, 2009
384
Just a quick question with a simple answer I hope. Does the void main() function continuously loop like the while(1) function does, or does it run through and then stop?
 

tshuck

Joined Oct 18, 2012
3,534
Just a quick question with a simple answer I hope. Does the void main() function continuously loop like the while(1) function does, or does it run through and then stop?
Depends on the processor. For embedded devices like microcontrollers, the behavior is undefined, it may, or may not, return to the first instruction location. This is why each program should have an infinite loop, so as to keep the behavior deterministic.
 

JohnInTX

Joined Jun 26, 2012
4,787
IF you exit main() at the bottom, the code returns to the C startup runtime (provided by the compiler). Usually, it cleans up and calls main again. Doing this is probably bad form in an embedded system since there is no 'operating system' to return control to (as would be the case on a PC etc.) and you are depending on the compiler to do your housekeeping..

Best to put a while(1) in main for embedded systems.
 

@android

Joined Dec 15, 2011
178
Just a quick question with a simple answer I hope. Does the void main() function continuously loop like the while(1) function does, or does it run through and then stop?
Simple main()function doesn't require a specific keyword or procedure for ending the program. In some programming languages, an END or EXIT command is required, but not in C. In the C language, the program ends when it encounters the last brace in the main() function. Hence in C main is not an infinite function. Wherein while(1) is an infinite loop.

Hope that helped! :)
 

WBahn

Joined Mar 31, 2012
29,932
Simple main()function doesn't require a specific keyword or procedure for ending the program. In some programming languages, an END or EXIT command is required, but not in C. In the C language, the program ends when it encounters the last brace in the main() function. Hence in C main is not an infinite function. Wherein while(1) is an infinite loop.

Hope that helped! :)
This is not necessarily the behavior in a non-hosted implementation, such as is often the case in embedded systems. See the earlier post by JohnInTX for a good description.
 

takao21203

Joined Apr 28, 2012
3,702
Returning from main by automatic means, not doing it on purpose, is a very bad programming style.

It is not done normally.

Leaving aspects undefined means you also in general increase the chance for such aspects to show their creepy effects.

If you have an operating system of any kind, yes, usually programs end at some point.

In C if you exit from main, at best you will do all the initialization again.

It is no difference for trivial programs, but larger programs will behave weird if the processor resets all the time.

You may get correct reactions for some part of the software, and sometimes display flickering.

Larger programs really don't work that way, as they use storage to determine further behaviour.
 

ErnieM

Joined Apr 24, 2011
8,377
Not that I would ever recommend exiting the main() function in a micro for any event except power OFF but it was bothering me to see the behavior referred to as "undefined," which to me means "I didn't look it up."

So I looked it up. Inside the C18 User's Guide (hlp18ug.chm) there is a section on the start-up code:

C18 User's Guide said:
After the start-up code sets up the stack and optionally copies initialized data, it calls the main() function of the C program. There are no arguments passed to main(). MPLABC18 transfers control to main() via a looped call, i.e.:
Rich (BB code):
loop:
   // Call the user's main routine
   main();
goto loop;
So by the well defined behavior (of this particular compiler) the start-up code is NOT run again if you drop out of the main() function.

One should leave one brain cell in active storage with this information in case the day comes when your program does weird things because of this very condition.
 

@android

Joined Dec 15, 2011
178
This is not necessarily the behavior in a non-hosted implementation, such as is often the case in embedded systems. See the earlier post by JohnInTX for a good description.
Looking at the question he posted I think it fits. He is not specifically asking about an embedded application. It is a general question so I gave general answer. :p
 

takao21203

Joined Apr 28, 2012
3,702
I have not seen it often, if at all.
If there is a programmed exit, it is done with a return, or with a special System function.
 

WBahn

Joined Mar 31, 2012
29,932
Looking at the question he posted I think it fits. He is not specifically asking about an embedded application. It is a general question so I gave general answer. :p
Ah, no. A general answer would apply both to hosted and non-hosted applications.

And the question makes much, much more sense if it is being asked about a non-hosted environment. I've never heard anyone working in a hosted environment who thought that main() would behave the same as while(1).
 

ErnieM

Joined Apr 24, 2011
8,377
How one exit's the main function is system dependent: it depends on the definition of main itself.

Is it:
void main (void); // typical for C in an embedded system

or is it:
int main(void); // PIC32 C, also for embedded systems

or perhaps:
int main(int argc, char *argv[]); // typical for C on a Unix system

In any case, a closing bracket } ends the main function, and if the code drops thru to that then main ends. The compiler will type check any return value if there is a value, but it does not check what is not there: you need not have a return statement in main.
 

JohnInTX

Joined Jun 26, 2012
4,787
I took a look at some listings for various compiled code I still have laying around to see what happens when you hit that closing bracket in main():

C51 - Franklin C for 8051 - Does an LJMP to main. No returning from there

C80 - Aztec C for 8085/Z80 - Depends on which startup is linked. One JMPs to main, another calls main but just does a RETurn after that. Presumably, some restart vector is on the stack (but I didn't see it). The CP/M library does a system call to start main and an exit(0) at main's end to return to the OS. This is classic DOS/UNIX/VMS etc behavior, passing back an error code as well.

X6063 (Archimedes) - Calls main and returns to the startup code which does another return.. to the BUFFALO monitor! Presumably, we were using BUFFALO at the time.

PV32 - Early Kiel / Franklin IDE based 8051-class compiler. Basic startup LJMP to main. No return. The replacement startup code for the target (a handheld terminal) included a jump back to start should main return.

HI-TECH PICC18 8.35_PL3 Always GOTOs main (to save stack per the manual). If main is contained by a looping construct (while(1) etc), that's it. If NOT, the compiler appends a GOTO back to the startup at the end of main, presumably to restart the program.

XC8 PIC10Fxx When no while(1):GOTO main to enter, GOTO 0 when exiting main.

XC8 PIC18Fxx GOTO main to enter. With/without while(1), appends a GOTO start to the end of main.

Those older compilers weren't as smart as newer ones e.g. PICC18 examines the code flow and tacks on a GOTO startup if you don't have a loop construct in main. It saves the code if you do. Of note is how all of the uCHIP compilers jump into main and jump back to startup to save stack. Smart.

Those early ones came with the STARTUP source so that you could adapt it to to the target environment e.g. BUFFALO monitor, for even more variances.

I can't envision a situation where, even if it were documented, I would want to exit main in an embedded system. What then? A well behaved system like HITECH, XC8 or MPC will restart the system mainly because it has nothing else to do with it. To the user, this looks like a reset BUT none of the code I looked at did any system cleanup such as reinitialize the peripherals or set the stack pointer. (To be fair, I didn't look that close but on baseline/midrange PICs you can't even access the stack pointer..). But, rather than exiting main to restart the program in the event of an unrecoverable error etc., I find it best to use the 18F 'reset' instruction or in the lower PICs, hang the watchdog to get a clean, all systems reinitialized restart.

With of all of this as well as the excellent points made by other posters here describing different possibilities, I stand by my original post; For typical ROM-based, no OS embedded systems, always have a loop construct in main and don't rely on the compiler generated startup code to save your bacon.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
the problem is so simple ,,,, disable the watchdog counter ,,,, that is all :)
Welcome to AAC. You have replied to an old thread so it is unlikely the original TS is still looking for an answer.
That said, the watchdog timer would not have anything to do with the original problem of what happens if you don't loop in main() in an embedded system. If anything, you would want the watchdog ENABLED so that if the C runtime does not recover after exiting main(), the processor could be reset when the watchdog times out and restart the system.
 

BobaMosfet

Joined Jul 1, 2009
2,110
Just a quick question with a simple answer I hope. Does the void main() function continuously loop like the while(1) function does, or does it run through and then stop?
main() is a function, whereas while() is a statement. The two things are viewed differently by the compiler and ultimately the processor.
 

Papabravo

Joined Feb 24, 2006
21,094
main() is a function, whereas while() is a statement. The two things are viewed differently by the compiler and ultimately the processor.
Without a looping construct inside of the main() function it will return after executing the last statement before the closing curly brace. What happens next is compiler dependent. You have to locate and examine the C Startup file that is part of every embedded C program. From that assembly language file you can determine exactly what will happen. No general purpose answer will be accurate or reliable; you must dig (excavate(?)) for the answer.
 

BobaMosfet

Joined Jul 1, 2009
2,110
Without a looping construct inside of the main() function it will return after executing the last statement before the closing curly brace. What happens next is compiler dependent. You have to locate and examine the C Startup file that is part of every embedded C program. From that assembly language file you can determine exactly what will happen. No general purpose answer will be accurate or reliable; you must dig (excavate(?)) for the answer.
Not sure why you are replying to me. All I stated was that a function and a statement are different from one another, since the OP didn't seem to know this. Discussing entry points, stack frames, jump tables, and assembly language is well beyond what the OP needs at this point.
 

WBahn

Joined Mar 31, 2012
29,932
I don't think PB was so much replying TO you as much as just expanding on the information provided BY you -- and the point he is making is very relevant in a non-hosted environment, which if I recall (from three years ago) the TS was working with at the time.
 

Papabravo

Joined Feb 24, 2006
21,094
I don't think PB was so much replying TO you as much as just expanding on the information provided BY you -- and the point he is making is very relevant in a non-hosted environment, which if I recall (from three years ago) the TS was working with at the time.
This is precisely the case. I have had occasion to dissect several C startup files for about a dozen embedded processor/compiler combinations. IMHO the ones that do the best job actually force a hardware RESET by hook or by crook when there is a return from main. In most cases it is essential to draw as much attention to this behavior as possible. That said I can imagine a mission critical application in which a softer recovery mechanism might be employed. It is ALWAYS to the benefit of the embedded engineer to understand precisely what the canned compiler code is doing to(for) you. Only in that fashion can you inoculate yourself and your code.
 
Top