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