本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第3章,建议19,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
建议19:避免使用嵌套的“?:”
在C语言中,“?:”运算符是if/else语句的另外一种表示形式,其一般形式如下所示:
Exp1 ? Exp2 : Exp3
其中,Exp1、Exp2 与 Exp3都是表达式。程序首先对Exp1 求值,如果 Exp1 的值为真时,就对Exp2 求值并将其求值结果作为整个问号表达式的值;否则,就对Exp3 求值并将其求值结果作为整个问号表达式的值。
由于问号表达式语法的简洁性,因此我们经常看到一些程序员在做判断时只用“?:”,而从不使用if/else语句。如下面的示例代码所示:
unsigned int f( int x)
{
return x>=1?1:0;
}
很显然,相对于if/else语句,这样的代码看起来更加简洁明了。但是,如果我们嵌套使用“?:”,那就不一样了。如下面的示例代码所示:
unsigned int f(unsigned int x)
{
return( (x<=1)?(1-x):(x==4)?2:(x+1) );
}
在上面的代码中,嵌套了两层“?:”,它实际等效于下面的代码:
unsigned int f(unsigned int x)
{
unsigned temp;
if(x <= 1)
{
if(x != 0)
{
temp = 0;
}
else
{
temp = 1;
}
}
else
{
if(x == 4)
{
temp = 2;
}
else
{
temp = x + 1;
}
}
return temp;
}
从上面的代码中可以看出,尽管嵌套使用“?:”可以使代码变得简洁,但代码的可读性却因此降低了不少。这个时候有的程序员或许会说,嵌套使用“?:”不仅使代码简洁,更重要的是它比if/else语句能够产生更加高效的代码。但实际情况并非如此,有兴趣的读者不妨试一试下面的代码,对两者做个比较。
unsigned int f(unsigned int x)
{
unsigned temp;
if( x <= 1 )
{
temp = 0;
if( x == 0 )
{
temp = 1;
}
}
else
{
temp = 2;
if( x != 4 )
{
temp = x + 1;
}
}
return temp ;
}
其实,使用“?:”运算符所存在的问题是:由于它很简单,容易使用,看起来好像是产生高效代码的理想方法。因此,程序员就不再寻找更好的解决方法了。更糟糕的是,有些程序员会将if/else语句全部转换为“?:”来获得所谓的高效解决方案。而实际上“?:”并不比if/else语句好,它们所产生的汇编代码也基本相同。
因此,为了能够提高程序的执行效率,我们应该将时间花在寻求可替代的高效算法上,而不是一味地追求以某个稍微不同的方式来实现同一个算法上。例如,我们可以将上面的代码修改成下面这种更直接的实现方法:
unsigned int f(unsigned int x)
{
assert( x >= 0 && x <= 4 );
if( x == 1 )
{
return 0 ;
}
if( x == 4 )
{
return 2 ;
}
return x + 1 ;
}
甚至,我们还可以使用下面的列表方式来实现上面的示例程序,如下面的代码所示:
unsigned int f(unsigned int x)
{
assert( x >= 0 && x <= 4 );
static const unsigned temp[] ={1,0,3,4,2 };
return temp[x] ;
}