3 ms·
My recent WTF with C and C++ was that I found out that C++ compiler can just throw away infinite loop (and clang does that), while C compiler must not throw it
by vbezhenar 3y ago
My recent WTF with C and C++ was that I found out that C++ compiler can just throw away infinite loop (and clang does that), while C compiler must not throw it away and must compile it as expected. It's all according to the standard. For example it's a typical construct for embedded software.
That solidified my opinion that C and C++ are very different languages despite naive view being that C is just a subset of C++. They're fundamentally different.
- ryao 3y agoHere is another. In C, union types support type punning. In C++, they broke that guarantee, so if you compile C code that uses a union type as C++ code, it could be broken. It would be nice to know why they broke this. My guess is that it violated the strong type philosophy of C++ and thus had to be broken on ideological grounds. C++ also broke implicit void pointer conversions, but at least that one had the reason that it was incompatible with function overloading. Not that anyone involved with C++ would tell you this. Instead, they provide bad C code that breaks the strict aliasing rule and claim that breaking implicit void pointer conversions somehow follows from it when in reality that is a non-sequitur: https://www.stroustrup.com/bs_faq2.html#void-ptr https://www.stroustrup.com/bs_faq2.html#void-ptr
- charleslmunger 3y agoWhen would you want a loop that does not terminate and does not perform I/O, read/write a volatile, synchronize with another thread, or perform an atomic operation?
- ryao 3y agoOne time the heat at my place went out and I wanted to repurpose my machine as a space heater. In such a scenario, such a loop is desirable. Termination can be done by the operating system.
- macksd 3y agoI have a System76 Serval and I highly recommend it, especially for your use case.
- maximus-decimus 3y agorelevant xkcd https://xkcd.com/1172/ https://xkcd.com/1172/
- ryao 3y agoIt is a very important feature. :P
- bit-hack 3y agoa busy loop waiting for an interrupt to fire?
- sweetjuly 3y agoThis is reasonable, but for the sake of your power budget I hope you use a wait-for-interrupt instruction instead rather than just spinning :)
- deleted 3y ago[deleted]
- isopede 3y agoThis happens regularly in the embedded space. Exception and fault handlers, for example.
- vbezhenar 3y agoFor example when my algorithm is driven by interrupts and "user code" need to do nothing. One approach is to use something like WFI instruction in the loop, but this instruction has its own issues, for example I experienced issues with attached gdb on some chinese STM32 clones. Using busy loop worked just fine. Using "unused" volatile also works, but it incurs SRAM traffic, which might slow down DMA and cause other effects. So ideally it should be simple empty loop compiled to `b .` instruction (jump to itself). Another infinite loop usage is for abort() or exit() handler, as a crash place. For this use-case, using "unused" volatile does not cause issues, because device is already crashed, however it still feels wrong.
- notfed 3y agoThrow away? Hopefully that means replace it with a crash? If it's just carrying on, that sounds bad.
- junon 3y agoYes, throw away entirely.
- muldvarp 3y ago> If it's just carrying on, that sounds bad. Why? If you are an experienced C or C++ programmer you know about these quirks. Replacing an infinite loop without side effects with a crash sounds about as "bad" as optimizing it away.
- lpribis 3y agoWhat about baremetal embedded system code where there is no concept of a 'crash'? Sure you can emit a trap instruction/bus fault/etc, but what to emit for the trap handler code?
- vbezhenar 3y agoIn the linked example clang just compiled function to nothing. In practice it means that CPU will run over random memory after calling this function. It probably will cause a crash, but may be it'll format a disk, who knows. https://godbolt.org/z/zTz1488P3 https://godbolt.org/z/zTz1488P3
- wzdd 3y agoI got curious about this. It seems that C11 at least is much closer to the C++ behaviour: under certain conditions, compilers can assume that loops terminate even if they can't prove it. See https://krinkinmu.github.io/2021/12/12/pain-of-infinite-loops.html https://krinkinmu.github.io/2021/12/12/pain-of-infinite-loop... for example and the relevant part of the standard, N1509 (Clang's compatibility chart referencing that: https://clang.llvm.org/c_status.html https://clang.llvm.org/c_status.html). Importantly (see for example https://blog.regehr.org/archives/140 https://blog.regehr.org/archives/140) it's not that the standard previously explicitly forbade this sort of optimisation, it's just that it wasn't very clear and compiler writers interpreted it differently. So in summary, yes, they're different languages, but "modern" C is is less different for this particular thing.
- ryao 3y agoHow they treat infinite loops that obviously never terminate (e.g. while (1)) is probably of greater interest. The first link gives this code: namespace { void Panic() { while (1); } } // namespace extern "C" void kernel() { Panic(); } The clang++ really does optimize this away: https://godbolt.org/z/1Wf135918 https://godbolt.org/z/1Wf135918 The same thing happens when I let clang++ compile a C version as C++: https://godbolt.org/z/MxcGfWhej https://godbolt.org/z/MxcGfWhej However, if I compile it as C with clang, I get an infinite loop: https://godbolt.org/z/x63fo33Wa https://godbolt.org/z/x63fo33Wa