編譯系統對求值順序都有明確規定,例如對「++」和「--」指令,不同的編譯系統對它們的處理順序不相同,稱這類指令為依靠方向性的指令。
為了提高可靠性和可移植性,就要避免使用依靠編譯系統的語法。所謂不依靠編譯系統,就是指避免依靠方向性(如「++」指令)。編程時絕對不能偷懶,在需要明確計算方向的場合,一定要明確。這時可以用括號明確計算方向,或者改變編寫方法。
下面的程序段就是使用了方向性指令。
i=0 ; while (i<n ) y[i] = x[i++] ;
在這個程序段中,「x[i++]」就是假設了求值的順序。這在有些機器上可能是正常的,但在有些機器上則不一定。應該避免「x[i++]」這種寫法,建議寫成
i=0 ; while (i<n ) { y[i]=x[i] ; i++ ; }
的形式。也可以改變設計方法,例如,一般更建議寫成
for ( i=0 ; i<n ; i++ ) y[i]=x[i] ;
的形式。
【例12.1】下面的程序用來求數組a兩項之間的差值,試分析程序存在的問題。
#include <stdio.h> void main () { int i=0 ,j=0 ,a[6]={2 ,7 ,11 ,-45 ,88 ,43} ,b[6] ; while (b[i] !=0 ) { b[j++]=a[i++]-a[i] ; } for (i=0 ;i<5 ;i++ ) printf (\"b[%d]=%d \" ,i ,b[i] ); printf (\"n\" ); }
【分析】在執行語句
b[j++]=a[i++]-a[i] ;
的時候,主觀上以為用i作為第1個值,遞加i作為第2個值。其實並非如此,在一個運算表達式中,它們變成同一個下標,所以計算的值均為0。
由此可見,編譯器能決定一些分支程序的執行順序,所以執行結果具有系統和編譯器的雙重依賴性,是不好的編程方法。
像「++」和「--」之類的運算符,應該單列一行。必要時還要顯式地限制運算順序。
修改後的程序取消了變量j,都利用i計算,簡單明瞭。
#include <stdio.h> void main () { int i=0 ,j=0 ,a[6]={2 ,7 ,11 ,-45 ,88 ,43} ,b[6] ; while (a[i] !=0 ) { b[i]=a[i] ; i++ ; b[i-1]=b[i-1]-a[i] ; } for (i=0 ;i<5 ;i++ ) printf (\"b[%d]=%d \" ,i ,b[i] ); printf (\"n\" ); }
運算結果如下:
b[0]=-5 b[1]=-4 b[2]=56 b[3]=-133 b[4]=45
在書寫程序時,也要注意檢查依賴系統的語句。例如「++」的寫法是否正確。在某些場合下,++i和i++的效果一樣,例如在for循環語句
for ( i=0 ; i<100 ; ++i )
中,將它寫成++i和i++都是可以的(儘管在效果一樣的情況下,推薦前置寫法),但在某些場合就不能隨意交換。
【例12.2】寫法效果不一樣的例子。
#include <stdio.h> int main () { int x , y , i=2 , j=2 ; y = 2 + ++i ; x = 2+ j++ ; printf (\"y=%d , x=%d , i=%d , j=%dn\" , x , y , i , j ); return 0 ; }
程序運行結果如下:
y=4 , x=5 , i=3 , j=3
一定要注意運算表達式的順序。如果怕混淆,乾脆採取給定順序的寫法。例如將程序寫成如下形式,運行結果一樣。
【例12.3】避免誤解的例子。
#include <stdio.h> int main () { int x , y , i=2 , j=2 ; y = 2 + i ; ++i ; j++ ; x = 2+ j ; printf (\"y=%d , x=%d , i=%d , j=%dn\" , x , y , i , j ); return 0 ; }
當然,可以用「i=i+1」替代「++i」。但兩者是有區別的,在「++i」執行中i只計算一次,而在「i=i+1」執行中i要計算兩次。C語言之所以提供增量和減量運算符,不僅是為了程序書寫方便,也是考慮到編譯器的效率。一般硬件CPU都提供了增量和減量指令,因此增減運算可以直接採用這些指令實現,從而提高程序效率。
需要注意的是,老版本的C編譯器會將「a=-5;」理解為「a=a-5;」,而不是「a=(-5)」,所以建議對可能產生問題的地方均予以迴避。例如VC6.0把如下語句
a=b/*p ;
中的「*」號作為註釋,出現綠色字體。必須在「/」與「*」之間留有空格。改為
a= b/ *p
或者
a= b/ (*p );
當然也要避免寫作
a=/*b ;
有些屬於准兩義性錯誤,編譯器檢查不出來,有時會造成嚴重的錯誤。
對於這類運算符,也要注意表達式的正確性。例如下面求和循環語句
for (i=1 ; i<=100 ; ++i ) sum += sum+i ; printf (\"sum=%d\" , sum );
輸出sum=-102而不是5050,就是將「sum+=i;」錯為「sum+=sum+i;」造成的。有時可以用顯式表述以避免錯誤,如「sum=sum+i;」。