Linux gcc for 循環中 i=i++ 會形成死循環問題及 ++i / i++ 彙編分析

在把 Windows 程序移植到 Linux 時遇到了死循環,最後定位到了相似這種的語句 for (i = 0; i < 1; i = i++),linux

別問我是誰寫的,爲何這麼寫(淚目)。緩存

根據我本身的感受, i = i++ 應該等價於 i++(C標準中 i=i++ 的行爲未定義), Windows 上確實是這樣,但 Linux 不是,這應該是編譯器差別形成的。spa

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

那麼問題來了,爲何會這樣呢?內存

用 arm-linux-gcc  -S  i.c 彙編一下,編譯結果和源碼以下(gcc 彙編的代碼不太好看,因此用了 arm 版的):編譯器


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

mov r3, #0       (把常數值賦值給 r3,至關於 r3=0)it

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,爲了移植性,不能相信編譯器。

相關文章
相關標籤/搜索