“悬挂”else问题,应该是我们最熟悉不过的一个问题了。此问题也不是C/C++所独有。即使有多年软件开发经验的资深程序员也常常深受其害。
我们首先理解一下,什么是“悬挂”else问题?为了使我的描述更形象、你更容易理解;我们看下面这个例子。
#include <stdio.h>
int main()
{
int x = 0;
int y = 1;
if(x == 0)
if(y == 0) printf("x == 0 && y == 0\n");
else
printf("x!=0\n");
return 0;
}
这段代码的本意我想应该是:对于x=0这种情形,如果y=0输出“x==0 && y==0”,否则程序不做任何处理。对于x!=0这种情形,程序输出“x!=0”。
但是,这段代码实际执行情况也许会让你大惊失色。原因在于c++从C继承了这条规则:else始终与同一对括号内最近的未匹配的if结合。按照这条规则,上面这段代码实际被执行的逻辑应该是这样的:
int x = 0;
int y = 1;
if(x == 0)
{
if(y == 0)
{
printf("x == 0 && y == 0\n");
}
else
{
printf("x!=0\n");
}
}
return 0;
从这段代码,我们可看出:如果x不等于0,程序将不会做任何处理操作,直接return0;。如果要得到原本由代码缩进所体现的编程者的本意,程序应该修改成整这样:
int x = 0;
int y = 1;
if(x == 0)
{
if(y == 0)
printf("x == 0 && y == 0\n");
}
else
{
printf("x!=0\n");
}
return 0;
可以看出,现在else与第一个if结合,即使它距离第二个if更近也是如此。因为这时第二个if已经被一对大括号“封装”了。
现在我们对“悬挂”else问题已经彻底了解,然而如何避免此问题呢?我们先把这个问题放到一旁,看一下Bash Shell语言的if-else实现方式。Bash shell脚本语言在if语句后使用了收尾定界符来显示地说明if语句结束。我们看下面这段脚本代码:
#!/bin/sh
if [ ${SHELL} = "/bin/bash" ]; then
if [“$LOGNAME” != “root”]; then
echo “you need to be root to run this script” >&2
fi
else
echo "your login shell is not bash but ${SHELL}"
fi
像上述这种fi强制首尾符完全避免了“悬挂”else问题,而付出的代价仅仅是程序稍微变长了一点儿。
在C++中,我们也可以通过宏定义达到Bash shell所达到的效果。考虑下面这种实现:
#define IF {if(
#define THEN ) {
#define ELSE } else {
#define FI }}
这样,上例中的C++程序可改写成:
IF x == 0 THEN
IF y == 0 THEN
printf("x == 0 && y == 0\n");
FI
ELSE
printf("x!=0\n");
FI
这种方案确实解决了“悬挂”else问题,我想如果你是一个未接触过bash shell脚本语言的新手,我想当你看到这段代码时,你肯定会抓狂。我们可这么总结这种方案:这种方案所带来的问题比它所解决的问题更糟糕。
但是,对于“悬挂”else问题有更好的解决方案吗?答案是有的。解决这一问题最佳方案是让我们不屑的优秀的编码风格。也就是在if和else之后加上一对大括号,不论if-else之间有几条语句,也不论else后有几条语句。看下面这种编码解决方案:
int x = 0;
int y = 1;
if(x == 0)
{
if(y == 0)
{
printf("x == 0 && y == 0\n");
}
}
else
{
printf("x!=0\n");
}
return 0;
请谨记
|