Tried to use "int main(void)" - what's wrong?

Hi all,

I looked at "main.cpp" and discovered that all it does is call a function named "init();", then runs setup() and finally runs loop() in an endless loop.

So as a "control", I tried this:

void setup (void)
{
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
}

void loop (void) { ; }

Of course, it works.

Then I tried this:

int main (void)
{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        return 0;
}

This "sort of" works, but it only prints three characters (i.e. "Thi"). Also, the "int main(void)" sketch compiles to 1780 bytes while the "setup/loop" sketch compiles to 1844 bytes. Exactly a 64 byte difference. So obviously something is missing, but I don't know WHAT.

Note that I'm doing this just out of curiosity... can't learn if you don't tinker!

Anyone have any ideas? Thanks!

-- Roger

Don't return from main. When main returns, the run-time library disables interrupts and enters an endless loop.

On my 1.0.2 Arduino setup, main.cpp is:

#include <Arduino.h>

int main(void)
{
        init();

#if defined(USBCON)
        USBDevice.attach();
#endif
        
        setup();
    
        for (;;) {
                loop();
                if (serialEventRun) serialEventRun();
        }
        
        return 0;
}

So, I imagine you need to call serialEventRun() if it exists to print out the remaining characters (serialEventRun is presumably a pointer to a function that is NULL if you didn't include the serial driver, and points to a function to call if you did include the driver). You will probably need to call it multiple times until all of the characters are written.

The majority of the 64 bytes are very likely prolog / epilog for loop.

Then I tried this:

Code:
int main (void)
{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        return 0;
}

So what happens when the return 0; executes?
In a micro-controller where there is no underling OS to return to, main should never be allowed to return. That is why the arduino supplied main() has in it a loop function that cannot end.

Lefty

that would mean that this would work?

int main (void)
{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        while(1);
}

Wow! You guys are amazing! It works:

int main (void)
{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        for(;;) { ; }
}

I added the last line so main() wasn't required to return (because it never does!) and now it works. The above code compiles to 1768 bytes which is SMALLER than the first two tests.

Thanks a bunch. I would have never seen that. I always miss things that are right in front of my face!

Thanks again!

-- Roger

robtillaart:
that would mean that this would work?

int main (void)

{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        while(1);
}

No, as I said earlier, you likely need to call serialEventRun() in order to print out the characters in the while loop. I personally think putting the semi-colon on the line of the while is bad coding form, as it is easy to miss it when humans are looking at the code.

robtillaart:
that would mean that this would work?

int main (void)

{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        while(1);
}

Just tried it. "while(1)" works and it compiles to the same size (1768 bytes). I wonder if there is an "advantage" to using one over the other?

MichaelMeissner:

robtillaart:
that would mean that this would work?

int main (void)

{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        while(1);
}

No, as I said earlier, you likely need to call serialEventRun() in order to print out the characters in the while loop. I personally think putting the semi-colon on the line of the while is bad coding form, as it is easy to miss it when humans are looking at the code.

Main.cpp calls "serialEventRun()" conditionally if "serialEventRun" exists (which in my test code it does not).

Forcing main() to never return was the answer.

Krupski:

robtillaart:
that would mean that this would work?

int main (void)

{
        init();
        Serial.begin(115200);
        Serial.print("This is a test\r\n");
        while(1);
}

Just tried it. "while(1)" works and it compiles to the same size (1768 bytes). I wonder if there is an "advantage" to using one over the other?

I think the while(1) is a little more self explanatory then the if(;;;;;;;;;;;;;;:wink: BS. :smiley:

Lefty

retrolefty:

Krupski:

robtillaart:
that would mean that this would work?

int main (void)

{
       init();
       Serial.begin(115200);
       Serial.print("This is a test\r\n");
       while(1);
}

Just tried it. "while(1)" works and it compiles to the same size (1768 bytes). I wonder if there is an "advantage" to using one over the other?

I think the while(1) is a little more self explanatory then the if(;;;;;;;;;;;;;;:wink: BS. :smiley:

Lefty

I wonder though... for the "while(1)" code to run, the processor needs to keep checking if "1" is true. I assume that takes "X" number of clock cycles per loop around.

Now the code "for (;:wink: { ; }" I'm not sure of. There are no values for the processor to test, so would it run "faster" per loop?

MichaelMeissner:
No, as I said earlier, you likely need to call serialEventRun() in order to print out the characters in the while loop.

That is not necessary. Ironically, serialEventRun has nothing to do with Serial.

Krupski:
Just tried it. "while(1)" works and it compiles to the same size (1768 bytes). I wonder if there is an "advantage" to using one over the other?

There is. Whichever one you are more likely to recognize 12 months from now is the correct one.

For me, see retrolefty's reply #10.

Krupski:
I wonder though... for the "while(1)" code to run, the processor needs to keep checking if "1" is true. I assume that takes "X" number of clock cycles per loop around.

Now the code "for (;:wink: { ; }" I'm not sure of. There are no values for the processor to test, so would it run "faster" per loop?

In both cases, the compiler is "smart" enough to recognize the condition is always true and generate the least possible amount of code (a single unconditional jump).

retrolefty:
I think the while(1) is a little more self explanatory then the if(;;;;;;;;;;;;;;:wink: BS. :smiley:

while(1) also formats better on the forum. :wink:

You mean to imply that I didn't mean that to happen on purpose? Where is the trust around here? :wink:

Lefty

That's funny! I had to disable smilies in one of my posts because the semicolon and right parentheses transformed from code to a wink! LOL!

Ironically, serialEventRun has nothing to do with Serial.

Yes, it does. It checks to see that there is serial data to be read and, if there is, it calls the serialEvent() function, if there is one in the sketch.

It has nothing to do with interrupts continuing to happen, to shift the buffered serial data out the port, as Michael was suggesting was needed. That fact that return disables interrupts is what prevents the rest of the buffered data from being shifted out.

PaulS:

Ironically, serialEventRun has nothing to do with Serial.

Yes, it does. It checks to see that there is serial data to be read and...

Sorry about that. Should have checked.