编译系统对求值顺序都有明确规定,例如对“++”和“--”指令,不同的编译系统对它们的处理顺序不相同,称这类指令为依靠方向性的指令。
为了提高可靠性和可移植性,就要避免使用依靠编译系统的语法。所谓不依靠编译系统,就是指避免依靠方向性(如“++”指令)。编程时绝对不能偷懒,在需要明确计算方向的场合,一定要明确。这时可以用括号明确计算方向,或者改变编写方法。
下面的程序段就是使用了方向性指令。
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;”。