For loop doesn't terminate in an int function without a return statement

Viewed 166

On an Arduino Uno, for loops behave very strangely when in an int function that doesn't return anything.

void setup() {
    Serial.begin(9600);
}

void loop() {
    foo();
    Serial.println("Never reached");
}

int foo() {
    for (int i = 0; i < 9; i++) {
        Serial.println(i);
    }
}

This outputs the following, and continues on indefinitely looping through ASCII...

0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
@
A
B
C
D

Also, having the for condition as i < 12 makes it just count up numerically forever, none of the ASCII output.

This is all fixed by adding return 0; to foo(), but I'm curious why this happens. Any ideas?

3 Answers

The C++ language has a notion of undefined behavior. It is possible to write code that does not constitute a program.

Once example of undefined behavior is not returning a value from a function declared as int foo(). From the standpoint of an optimizing compiler the function never returns, since it's an impossibility to return from int foo() without returning an int value, so it optimizes away the end-of-loop condition.

Check your compiler warnings - there should be a warning about a possible missing return.

If you didn't intend to return anything from foo(), then it should be declared void foo().

Code with bugs will behave in strange and unpredictable ways. As you noticed, when you fix the bug, the problem goes away.

In this case, the compiler probably noticed the absence of a return statement and concluded that therefore the loop must never terminate. Since it is impermissible to fail to return something from a function that say it will return something, the compiler deduced that code was unreachable. Thus it removed the test for loop termination as an optimization.

The compiler is permitted to assume that your code is correct (except where diagnostics are required) and use that to optimize your code. This has huge benefits for code that has no bugs.

It would be incredibly impractical to require the compiler to assume that your code might have bugs in it. It would also be pointless, after all, there's nothing sensible the compiler can do at run time when code that must return a value fails to return value.

You might think a perfect compiler would generate an error at compile time -- but how could it? How does it know that Serial.println(i); always returns when it compiles this code?

It is strongly recommended to add a return statement to any non-void function in C++. You just need to change your function type to void or add return statement to it.

#1:

void foo() {
   Serial.println("foo");
}

#2:

int foo() {
   Serial.println(""foo);
   return 0;
}
Related