再也不要討論類似(i++)+(i++)+(i++)表示式的值了!
阿新 • • 發佈:2019-02-07
研究
自增操作符的誤用
C語言標準並沒有詳細地規定一個表示式該如何求值,如3 * a + 5 * b中先算哪個乘法;表示式a = f1( ) + f2( )中先呼叫函式f1還是先呼叫函式f2;表示式( ) * ( )中,先對哪個括號裡的子表示式求值。雖然不同的編譯系統對子表示式的求值順序有著不同的優化原則,但是,通常情況下一個表示式在不同的編譯系統中會表現為相同的值。自增操作符的作用是讓變數自增1,但是,誤用自增操作符會引起一些麻煩,具體地說,就是會出現一些在不同的編譯系統中可能有不同值的表示式。
如有int i = 2時,表示式(i++) + (i++) + (i++)的值是多少呢?
子表示式i++求值時一方面表示式的值是2,另一方面求值操作將使變數i的值自增1,當變數i還是其它子表示式的運算元時,問題就來了:變數i的值是原值還是加1後的新值呢?
在VC6.0中,第一個子表示式i++求完值後,其它子表示式中出現的變數i的值還沒有改變,依然是2。表示式(i++) + (i++) + (i++)的值為6(2+2+2),求完值後,變數i會執行自增操作3次,其值會變成5。
在TC中,第一個子表示式i++求完值後,變數i會立即執行自增操作,因此,第二個子表示式中變數i的值已經是3了。表示式(i++) + (i++) + (i++)的值為9(2+3+4)。
如何評價這個“值不確定”的表示式呢?
首先,這個表示式不“合法”。嚴格地說C語言程式中不能出現類似的表示式,它是非法的,雖然它能通過編譯系統的檢查並也能輸出一個結果。
其次,程式沒有必要出現這樣的表示式。可讀性是程式最重要的屬性,如果需要值為9的表示式,則原表示式可改寫為i+(i+1)+(i+2)和i+=3兩個表示式;如果需要值為6的表示式,則原表示式可改寫為i+i+i和i+=3兩個表示式。改寫後的表示式既簡單又具有確定的值。
誤用自增操作符也會影響函式的輸出。如有int j = 3,函式呼叫語句printf("%d,%d\n", j, j++);的輸出值也不確定。呼叫函式時,C語言標準沒有明確規定引數的求值順序,但TC和VC都按自右向左的順序對實參求值。在VC中,先計算表示式j++的值為3,但它不馬上執行自增操作,因此,對實參j求值的結果還是3,輸出結果為3,3。在TC中,先計算表示式j++的值為3,然後馬上執行自增操作,因此,對實參j求值的結果是4,輸出結果為4,3。
程式設計時不要以這種方式使用自增操作符。當希望輸出3,3時,可以將上面的語句改寫為printf ("%d,%d\n", j, j);和++j;兩條語句。當希望輸出4,3時,可以將上面的語句改寫為i = j++;和printf("%d,%d\n", j, i);兩條語句。
強調:
表示式中出現了子表示式i++(或++i或--i或i--)後,變數i就不要再出現在其它子表示式中了。
注意:
VC6.0採用了不同的原則處理前置和後置自增(自減)操作符。前置自增操作符會先執行自增操作,如有int i = 2時,表示式++i + i的值為6(3+3),但是表示式(++i) + (++i)的值卻是8(4+4即先執行兩次自增操作,第一次使變數i的值變為3,第二次使變數i的值變為4,然後再求值)。表示式(++i) + (++i) + (++i)的值是多少呢?(4+4+5=13,子表示式(++i) +求完值後,原表示式變成了8+(++i)。)
討論:
(1) 如何看待C語言中值與編譯系統相關的表示式?
(2) 使用自增操作符時應避免出現什麼情況?
(3) 在VC6.0中表達式++i和表示式i++都可以使變數i自增1,但它們的執行過程相同嗎?
提示:
(1) 此類表示式的共同特點是可讀性和實用性都非常差。
自增操作符的誤用
C語言標準並沒有詳細地規定一個表示式該如何求值,如3 * a + 5 * b中先算哪個乘法;表示式a = f1( ) + f2( )中先呼叫函式f1還是先呼叫函式f2;表示式( ) * ( )中,先對哪個括號裡的子表示式求值。雖然不同的編譯系統對子表示式的求值順序有著不同的優化原則,但是,通常情況下一個表示式在不同的編譯系統中會表現為相同的值。自增操作符的作用是讓變數自增1,但是,誤用自增操作符會引起一些麻煩,具體地說,就是會出現一些在不同的編譯系統中可能有不同值的表示式。
如有int i = 2時,表示式(i++) + (i++) + (i++)的值是多少呢?
子表示式i++求值時一方面表示式的值是2,另一方面求值操作將使變數i的值自增1,當變數i還是其它子表示式的運算元時,問題就來了:變數i的值是原值還是加1後的新值呢?
在VC6.0中,第一個子表示式i++求完值後,其它子表示式中出現的變數i的值還沒有改變,依然是2。表示式(i++) + (i++) + (i++)的值為6(2+2+2),求完值後,變數i會執行自增操作3次,其值會變成5。
在TC中,第一個子表示式i++求完值後,變數i會立即執行自增操作,因此,第二個子表示式中變數i的值已經是3了。表示式(i++) + (i++) + (i++)的值為9(2+3+4)。
如何評價這個“值不確定”的表示式呢?
首先,這個表示式不“合法”。嚴格地說C語言程式中不能出現類似的表示式,它是非法的,雖然它能通過編譯系統的檢查並也能輸出一個結果。
其次,程式沒有必要出現這樣的表示式。可讀性是程式最重要的屬性,如果需要值為9的表示式,則原表示式可改寫為i+(i+1)+(i+2)和i+=3兩個表示式;如果需要值為6的表示式,則原表示式可改寫為i+i+i和i+=3兩個表示式。改寫後的表示式既簡單又具有確定的值。
誤用自增操作符也會影響函式的輸出。如有int j = 3,函式呼叫語句printf("%d,%d\n", j, j++);的輸出值也不確定。呼叫函式時,C語言標準沒有明確規定引數的求值順序,但TC和VC都按自右向左的順序對實參求值。在VC中,先計算表示式j++的值為3,但它不馬上執行自增操作,因此,對實參j求值的結果還是3,輸出結果為3,3。在TC中,先計算表示式j++的值為3,然後馬上執行自增操作,因此,對實參j求值的結果是4,輸出結果為4,3。
程式設計時不要以這種方式使用自增操作符。當希望輸出3,3時,可以將上面的語句改寫為printf ("%d,%d\n", j, j);和++j;兩條語句。當希望輸出4,3時,可以將上面的語句改寫為i = j++;和printf("%d,%d\n", j, i);兩條語句。
強調:
表示式中出現了子表示式i++(或++i或--i或i--)後,變數i就不要再出現在其它子表示式中了。
注意:
VC6.0採用了不同的原則處理前置和後置自增(自減)操作符。前置自增操作符會先執行自增操作,如有int i = 2時,表示式++i + i的值為6(3+3),但是表示式(++i) + (++i)的值卻是8(4+4即先執行兩次自增操作,第一次使變數i的值變為3,第二次使變數i的值變為4,然後再求值)。表示式(++i) + (++i) + (++i)的值是多少呢?(4+4+5=13,子表示式(++i) +求完值後,原表示式變成了8+(++i)。)
討論:
(1) 如何看待C語言中值與編譯系統相關的表示式?
(2) 使用自增操作符時應避免出現什麼情況?
(3) 在VC6.0中表達式++i和表示式i++都可以使變數i自增1,但它們的執行過程相同嗎?
提示:
(1) 此類表示式的共同特點是可讀性和實用性都非常差。
