1. 自增運算子(Increment Operator) 自增運算子 ++ 使運算元的值增 1。++ 可以置於運算元前面,也可以放在後面。例如: ++n ; n++ ; 這兩個語句產生的結果都是使 n 增 1,可以說沒什麼區別。使用以下語句得到的效果也是一樣的: n = n + 1 ; 儘管上面兩個語句中,++ 前置和後置沒有區別。但是,++ 前置和後置其實是有區別的。例如: int n = 1, post, pre; post = n++; pre = ++n; 對於 post = n++; 這個語句,n 的值被賦予 post 後,n 才增 1。也就是說,這個語句執行完後,post 的值是 1,而 n 的值變成 2。而 pre = ++n; 這個語句,n 先增 1,然後再把自增後的值賦予 pre。也就是說,這個語句執行完後,pre 的值是 3,n 的值也是 3。 由此可得,如果 ++ 前置,則 ++ 的運算元先增 1,然後再參與其它運算;如果 ++ 後置,則 ++ 的運算元先參與其它運算,然後才增 1。嚴格地說,前置 ++ 的運算元的值在被使用之前增 1,而後置 ++ 的運算元的值在被使用之後增 1。例如: int n = 5, post = 1, pre = 1; pre = ++n + pre; // 運算結束後 pre 為 7 n = 5; post = n++ + post; // 運算結束後 post 為 6 2. 自減運算子(Decrement Operator) 自減運算子 -- 使運算元的值減 1。-- 可以置於運算元前面,也可以放在後面。例如: --n ; n-- ; 自減運算子和自增運算子非常相似,區別只在於自減運算子使運算元減 1,而自增運算子使運算元增 1。例如: int n = 5, post = 1, pre = 1; pre = --n + pre; // 運算結束後 pre 為 5 n = 5; post = n-- + post; // 運算結束後 post 為 6 3. 優先順序 自增運算子和自減運算子的優先順序很高,只有圓括弧的優先順序比它們高。因此,n*m++; 表示 n*(m++); 而不是 (n * m)++; 。而且 (n * m)++; 是錯誤的。因為 ++ 和 -- 的運算元只能是可變左值(modifiable lvalue),而 n * m 不是。 注意,不要把優先順序和取值順序混淆了。例如: int x = 1, y = 2, z; z = (x + y++) * 3; // 運算結束後 z 為 9,y 為 3 用數字代替上面的語句得: z = (1 + 2) * 3; 僅當 y 的值被使用後,y 才會增 1。優先順序表明的是 ++ 僅作用於 y,而不是 (x + y)。優先順序也表明 y 的值何時被使用,但是 y 的值何時增 1 是由自增運算子的本質決定的。 當 y++ 是某個算術運算式的一部分時,您可以認為它表示“先使用 y 的值,然後自增”。類似地,++y 表示“先自增,然後使用自增後的值”。 ========================================================================== 以下內容引自《C 語言常見問題集》 原著:Steve Summit 翻譯:朱群英, 孫 雲 http://c-faq-chn.sourceforge.net/ccfaq/index.html http://www.eskimo.com/~scs/C-faq/top.html ========================================================================== 4.3 對於代碼 int i = 3; i = i++; 不同編譯器給出不同的結果, 有的為 3, 有的為 4, 哪個是正確的? 沒有正確答案;這個運算式無定義。參見問題 3.1, 3.7 和 11.32。 同時注意, i++ 和 ++i 都不同於 i+1。如果你要使 i 自增 1, 使用 i=i+1, i+=1, i++ 或 ++i, 而不是任何組合, 參見問題 3.10。 12.35 有人說 i = i++ 的行為是未定義的, 但是我剛在一個相容 ANSI 的編譯器上測試, 得到了我希望的結果。 面對未定義行為的時候, 包括範圍內的實現定義行為和未確定行為, 編譯器可以做任何實現, 其中也包括你所有期望的結果。但是依靠這個實現卻不明智。參加問題 7.4, 11.31, 11.32 和 11.34。 4.2 使用我的編譯器,下面的代碼 int i=7; printf("%d\n", i++ * i++); 返回 49?不管按什麼順序計算, 難道不該列印出56嗎? 儘管尾碼自加和尾碼自減操作符 ++ 和 -- 在輸出其舊值之後才會執行運算, 但這裡的``之後"常常被誤解。沒有任何保證確保自增或自減會在輸出變數原值之後和對錶達式的其它部分進行計算之前立即進行。也不能保證變數的更新會在運算式 ``完成" (按照 ANSI C 的術語, 在下一個 ``序列點" 之前, 參見問題 3.7) 之前的某個時刻進行。本例中, 編譯器選擇使用變數的舊值相乘以後再對二者進行自增運算。 包含多個不確定的副作用的代碼的行為總是被認為未定義。(簡單而言, ``多個不確定副作用" 是指在同一個運算式中使用導致同一對象修改兩次或修改以後又被引用的自增, 自減和賦值操作符的任何組合。這是一個粗略的定義; 嚴格的定義參見問題 3.7, ``未定義" 的含義參見問題 11.32。) 甚至都不要試圖探究這些東西在你的編譯器中是如何?的 (這與許多 C 教科書上的弱智練習正好相反); 正如 K&R 明智地指出, ``如果你不知道它們在不同的機器上如何?, 這樣的無知可能恰恰會有助於保護你。 4.7 我怎樣才能理解複雜運算式?``序列點" 是什嗎? 序列點是一個時間點(在整個運算式全部計算完畢之後或在 ||、 &&、 ? : 或逗號 運算子處, 或在函數調用之前), 此刻塵埃落定, 所有的副作用都已確保結束。 ANSI/ISO C 標準這樣描述:
在上一個和下一個序列點之間, 一個對象所儲存的值至多隻能被運算式的計算修改一次。而且前一個值只能用於決定將要儲存的值。
第二句話比較費解。它說在一個運算式中如果某個對象需要寫入, 則在同一運算式中對該對象的訪問應該只局限於直接用於計算將要寫入的值。這條規則有效地限制了只有能確保在修改之前才訪問變數的運算式為合法。例如 i = i+1 合法, 而 a[i] = i++ 則非法 (參見問題 3.1)。 參見下邊的問題 3.8。 |