Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

My 'favourite' bit of surprising (not undefined) behaviour I've seen recently in the C11 spec is around infinite loops, where

void foo() { while (1) {} }

will loop forever, but

void foo(int i) { while (i) {} }

is permitted to terminate...even if i is 1:

> An iteration statement whose controlling expression is not a constant expression, that performs no input/output operations, does not access volatile objects, and performs no synchronization or atomic operations in its body, controlling expression, or (in the case of a for statement) its expression-3, may be assumed by the implementation to terminate

To make things a bit worse, llvm can incorrectly both of the above terminate - https://bugs.llvm.org//show_bug.cgi?id=965.



It means that empty loops (loops with empty bodies) can be completely removed if the controlling expression has no side effects.

> This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven.

It means while(i) {} can be eliminated as if i were 0, because there are no side effects in the loop expression or the loop body, and what would be the point of the loop if it never terminated on a non-constant expression?

As an optimization, the optimizer is allowed to eliminate it as a useless loop with no side effects. If you really want an infinite loop, you can use while (1) {}.

There are cases where automatically generated C code might have empty loops which are useless.

If you really want to go to sleep, use pause() or similar. An infinite loop eats up CPU cycles.


It's quite common in embedded systems to have the fault handler end with an infinite loop, to give the programmer a chance to attach a debugger an inspect the call stack. Sometimes this behavior is turned on or off with a debug flag, which can trigger this unexpected optimization if the flag is not a compile time constant.


A halt instruction (HLT on x86) might also work.


You could also add a volatile declaration


You could always say

    if (flag) while (1);


Yes, that would make more sense. I have never seen this optimization actually bite anyone.


> If you really want to go to sleep, use pause() or similar. An infinite loop eats up CPU cycles

Yes but an infinite loop + sleep is okay, right?


From compiler's POW call to sleep() is side-effect.


This definition is actually required for the correctness of many standard compiler optimizations such as partial redundancy elimination and code motion.


What's the point of this?


If the optimizer can determine that "nothing happens" in the loop, it can optimize the loop away without attempting to determine whether or not the loop terminates.


It allows the optimizer to assume away the halting problem; all nontrivial loops are obligated to halt.


What's the point of this though? Why are you letting programmers write non-functional code? When does the loop exactly terminate? I'm guessing the standard discusses this but at this point idk if I care about memorizing more C trivia.


It's more useful in C++. Imagine a templated vector destructor:

    for(T* ptr = begin; ptr != end; ++ptr)
    {  destroy(ptr); }
For many types, 'destroy' will be empty (for example integers), so this just turns into:

    for(T* ptr = begin; ptr != end; ++ptr)
    { }
Which is an empty loop and can be optimised away -- assuming we can prove it isn't an infinite loop! Which can be quite hard sometimes (in this case, it needs that 'end' is some multiple of sizeof(T) bigger than begin).

Now in many cases you can prove these loops are finite, but in full generality it's quite hard, and it was considered easier to just let the compiler remove them.



> What's the point of this though? Why are you letting programmers write non-functional code?

He just told you. Because the only way to prevent it in general is to solve the halting problem.

> When does the loop exactly terminate?

In the general case this is provably impossible to determine.

(all you're seeing here is that the compiler authors felt no need to add special case logic to handle "trivial" cases of the halting problem. If the compiler sees any expression in a loop test, it assumes the loop will halt some of the time)


> He just told you. Because the only way to prevent it in general is to solve the halting problem.

I'm aware. I think that I might have misunderstood what the optimization really does.


The idea (I assume) is to let compilers optimize away loops without determining that they terminate. I.e. the rule is more aimed at loops which would terminate, but this lets compilers avoid proving that they do in fact terminate.


Grandparent presented this as a "surprising optimization" but I'd argue it's exactly what you'd expect when a compiler sees while(expression) -- he just happened to pick a trivial expression.


I read this as, will confuse the snot out of hapless newbie programmers trying to learn C via stepping though their code in an IDE. While providing no practical benefit to programmers writing production code.


It is necessary in order for the compiler to do transformation optimizations which do impact production code. Newbies shouldn't be writing production code without guidance anyways IMO.


Newbies should probably turn off optimization entirely.


No argument there, or at the very least whole program optimizations




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: