# C++ 有關迴圈的未定義行為？

## TL;DR

沒有 Side Effect 的無窮迴圈是未定義行為。

## 起源

Source: [https://twitter.com/PR0GRAMMERHUM0R/status/1623366075357270019/photo/1](https://twitter.com/PR0GRAMMERHUM0R/status/1623366075357270019/photo/1)

可以先猜猜這段 code 會有什麼輸出（x86\_64 clang 15.0.0 -O1）

```cpp
#include <iostream>

int main() {
    while (1);
    return 0;
}

void unreachable() {
    std::cout << "why?" << std::endl;
}
```

結果竟然會印出：（[Compiler Explorer](https://godbolt.org/z/qTrndzcWs)）

```plaintext
why?
```

## 為什麼

參考一些文章，大致上是說沒有 side effect 的迴圈可能會被一些 compiler 決定砍掉，例如：

```cpp
void collatz(unsigned int n) {
    while (n > 1) {
        if (n % 2 == 0) {
            n = n / 2;
        } else {
            n = 3 * n + 1;
        }
    }
}
```

會被編成 （[Compiler Explorer](https://godbolt.org/z/dz3Md399o)）

```plaintext
collatz(unsigned int):                            # @collatz(unsigned int)
        ret
```

這並不是因為 compiler 幫你在 unsigned int 範圍證明了 Collatz Conjecture ，而是他直接**假定**會跑完迴圈，並且由於沒有 side effect ，所以直接剪掉。

一開始的起源，則是被編成

```plaintext
main:                                   # @main
unreachable():                       # @unreachable()
        push    rbx
        mov     rbx, qword ptr [rip + std::cout@GOTPCREL]
        lea     rsi, [rip + .L.str]
        mov     edx, 4
        ...
```

進入 main 時，這直接進到 unreachable 。

## 額外的一些小細節

* 用 clang 11 編不會出現這件事：
    

```plaintext
main:                                   # @main
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
        jmp     .LBB1_1
```

* 用 gcc 編不會出現這件事：
    

```plaintext
main:
.L2:
        jmp     .L2
```

* 把 -O1 拿掉不會出現這件事：
    

```plaintext
main:                                   # @main
        push    rbp
        mov     rbp, rsp
        mov     dword ptr [rbp - 4], 0
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
        jmp     .LBB1_1
```

* x86/x64 msvc 19 不會出現這件事：
    

```plaintext
_main   PROC                                      ; COMDAT
$LL2@main:
        jmp     SHORT $LL2@main
_main   ENDP
```
