考虑下面的程序段:
if(x==0) if(y==0) error(); else{ z = x + y; f(&z); }
这段代码中编程者的本意是应该有两种主要情况,x等于0以及x不等于0.对于x等于0的情况,除非y也等于0(此时调用函数error),否则程序不作任何处理;对于x不等于0的情形,程序首先先将x与y之后赋值给z,然后以z的地址为参数来调用函数f。
然而,这段代码实际上所做的与编程者的意图相去甚远。原因在于C语言中有这样的规则,else始终与同一括号内最近的未匹配的if结合。如果我们按照上面这段程序实际上被执行的逻辑来调整代码缩进,大致是这个样子:
if(x==0){ if(y==0) error(); else{ z = x + y; f(&z); } }
也就是说,如果x不等于0,程序将不会做任何处理。如果要得到原来的例子中由代码缩进体现的编程者本意的结果,应该这样写:
if(x==0){ if(y==0) error(); } else{ z = x + y; f(&z); }
现在,else与第一个if结合,即使它离第二个if更近也是如此,因为此时第二个if已经被括号“封装”起来了。
有的程序设计语言在if语言中使用收尾定界来显式地说明。例如,在Algol68语言中,前面提到的例子可以这样写:
if x = 0 then if y = 0 then error if else z := x + y; f(z) fi
像上面这样强制使用收尾定办符完全避免了“悬挂”else的问题,付出的代价则是程序稍稍变长了一点。有些C程序员通过宏定义也能达到类似的效果:
#define IF {if( #define THEN ){ #define ELSE }else{ #define FI {{
这样,上例中的C程序就可以写成
IF x == 0 THEN IF y ==0 THEN error(); FI ELSE z = x + y; f(&z); FI
如果一个C程序员过去不是长期浸淫于Algol 68语言,他会发现上面这段代码难于卒读。这样一种解决方案所带来的问题可能比它所解决的问题还要糟糕。
未经允许不得转载:TacuLee » C陷阱与缺陷之“悬挂”else