ser not declared as volatile. What this means is the compiler doesn't know it can be changed in an ISR.
ser is initialised to 1. In the
main() function, the compiler will examine the code and see that it gets to the
while(ser) loop. Now as far as it can see,
ser is never changed from the moment it is initialised to the moment the
while() loop is reached (because it can see that the
main() function doesn't call anything that changes the value). It can also see that
ser doesn't change within the
What this means is as far as the compiler can see, the
while() loop will always be entered because
ser is 1, but never exited because
ser is not changed anywhere that it knows the execution can reach.
It then says, well if the
while() loop will never exit, then there is no point checking the value of
ser, nor is there any point including any of the code after the loop (as it will never be reached). The whole loop will optimise to simply:
Which represents an infinite loop (it will jump back to itself and repeat forever).
But wait I hear you cry.
ser can be changed. It's modified in the ISR. Well, ok, it is, you know that, but the compiler doesn't. It is unaware that the processor can suddenly jump to another bit of code all on its own (well, when an interrupt is triggered actually). You need to tell it that this can happen.
By declaring something as volatile, it instructs the compiler to always load from memory the value of that memory whenever it is used. This means that the compiler can't assume that it will never change, because it has been told that it specifically must check. It is no longer able to say with certainty that the value in the memory is the value it put there at the beginning.