1. 程式人生 > >Linux gcc for 迴圈中 i=i++ 會造成死迴圈問題及 ++i / i++ 彙編分析

Linux gcc for 迴圈中 i=i++ 會造成死迴圈問題及 ++i / i++ 彙編分析

在把 Windows 程式移植到 Linux 時遇到了死迴圈,最後定位到了類似這種的語句 for (i = 0; i < 1; i = i++),

別問我是誰寫的,為什麼這麼寫(淚目)。

根據我自己的感覺, i = i++ 應該等價於 i++(C標準中 i=i++ 的行為未定義), Windows 上確實是這樣,但 Linux 不是,這應該是編譯器差異造成的。

--------------------------------------- 可 i 的分割線 No.0 --------------------------------------------------------------


那麼問題來了,為什麼會這樣呢?

用 arm-linux-gcc  -S  i.c 彙編一下,編譯結果和原始碼如下(gcc 彙編的程式碼不太好看,所以用了 arm 版的):


首先介紹一下出現的彙編指令:

mov r3, #0       (把常數值賦值給 r3,相當於 r3=0)

str r3, [fp, #-8] (把 r3 的值儲存到記憶體地址 [fp, #-8])

ldr r3, [fp, #-8] (把記憶體地址 [fp, #-8] 的值載入到 r3,和 str 相反)

add r2, r3, #1    (r2 = r3 + 1)

okey, 其實是先把 i 的原始值快取到 r3,然後加1的值賦給 r2,r2會更新 i 值(因為 i++), 最後 r3 也會更新 i 值(因為 i=),至於為何是這個順序,請呼叫大神吧。所以,i 的值會一直為0,導致文章開頭的 for 迴圈就死了。

--------------------------------------- 可 i 的分割線 No.1 --------------------------------------------------------------

為了好理解,我還彙編出了 j=i++,如下:


j = i++ : 還是先快取 i 的原始值,然後把加1的 i 值賦給 i,最後在把快取的 i 的原始值賦給 j(和 i = i++ 的順序一樣)。

j = ++i : 先更把加1的 i 值賦給 i,然後再取出 i 值賦給 j 。

--------------------------------------- 可 i 的分割線 No.2 --------------------------------------------------------------

此外,一直想看看i++ 和++i 的彙編有什麼不同,結果如下:


因為一直都聽過這個說法,for 迴圈中 ++i 的效率比 i++ 高,但從上圖中可以看成,在單獨的語句中,

++i 和 i++ 是一樣的(gcc 系列編譯器),不過還是推薦用 ++i,為了移植性,不能相信編譯器。