在C语言程序开发中,实现需求的解决方案往往不止一个。解决一个问题,程序员一般都能够设计出多个解决方案,并写出相应的C语言代码。可能有读者会觉得,解决问题的话,写出一种方法就可以了,给出多个方法没有意义,因为最终C语言程序也就只能使用其中一个而已,其他方案的工作都浪费了。
也许在其他编程语言的程序开发中,只要解决问题就可以,不过在C语言程序开发中,解决问题往往只是第一步,更多的工作一般都在接下来的精简代码和提升效率上。这是因为 C语言程序开发常常用在一些资源比较紧张,但是对效率要求又高的项目中。
在解决问题的多个解决方案中,各个方案的效率在不同的条件下使用,差异性常常比较大,所以C语言程序员要想写出优秀的程序,需要根据实际的情况,选择不同的方案。
编译时(compile time),和运行时(run time)
假设解决问题 P 有两套解决方案 funA() 和 funB()。不过,即使有两套解决方案,在实际应用中,也常只使用其中一套。确定解决方案后,作为C语言程序员,确定使用哪一套代码的方法有很多种,不过简要来说,这些选择方法可以分为“编译时”选择和“运行时”选择。
“编译时”选择代码主要借助C语言的预处理语法,下面是一个例子:
void solve()
{
#ifdef condition
funA();
#else
funB();
#endif
}
上面这段C语言代码使用了 #ifdef 预处理,如果希望使用解决方案 funA(),则C语言程序员应该 #define condition,此时 funB() 的代码不会参与编译。否则 solve() 就会使用解决方案 funB(),编译器不再编译 funA() 的代码。
究竟使用哪种解决方案,在编译时就确定了,所以这种选择方法称为“编译时”选择。
不过有时候C语言程序的用户希望可以在程序运行的过程中修改解决方案,这时显然就不能使用“编译时”选择了,因为要满足这种需求,funA() 和 funB() 的代码都必须参与编译。
void solve(bool cond)
{
if(cond)
funA();
else
funB();
}
麻烦的“运行时”选择
上面讨论的“运行时”选择相关的C语言代码非常简单,也非常常见,不过这种方法虽然能够解决问题,但是如果需要做选择的代码较多,整个C语言代码就显得啰嗦了。例如:
bool cond = user_choose;
void func1()
{
if(cond)
funA();
else
funB();
}
void func2()
{
if(cond)
funA();
else
funB();
}
显然,可能不止一处需要做解决方案选择,那么就得写多个 if 语句。要是 funcN() 非常多,对于程序员来说,就得写非常多的 if 语句,这显然太麻烦了,而且多处重复的C语言代码也不利于维护。对于C语言程序本身来说,做多个 if 判断也属于做多次重复工作,这会在一定程度上降低效率。
事实上,究竟使用哪种解决方案,只需要判断一次就可以了,请看:
bool cond = user_choose;
void (*funptr)();
void init()
{
if(cond)
funptr = funA;
else
funptr = funB;
}
void func1()
{
funptr();
}
void func2()
{
funptr();
}
上述C语言代码定义了函数指针 funptr,在 init() 函数中确定其指向,之后就无需再判断 cond 了。可以看出,使用函数指针后的代码相当简洁,而且也非常利于程序员维护,程序本身也无需做太多重复的处理。
事实上,不仅仅在选择解决方案时可以用到这个小技巧,在做程序向前兼容时,利用函数指针做代码选择也是一个不错的小技巧。
小结
本节主要介绍了C语言代码选择的两种方法,按照程序周期来说,可以简要分为“编译时”选择和“运行时”选择。在“运行时”选择中,借助函数指针常常可以精简代码,提升效率。