10

C语言程序开发中,if语句太多,整个程序太乱怎么办?

 3 years ago
source link: https://blog.popkx.com/c%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E4%B8%AD-if%E8%AF%AD%E5%8F%A5%E5%A4%AA%E5%A4%9A-%E6%95%B4%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%A4%AA%E4%B9%B1%E6%80%8E%E4%B9%88/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C语言程序开发中,if语句太多,整个程序太乱怎么办?

发表于 2019-08-31 20:08:35   |   已被 访问: 535 次   |   分类于:   C语言   |   暂无评论

if 分支语句是C语言程序开发中不可缺少的控制结构之一,它广泛存在于各个C语言程序中。甚至有程序员认为写程序就是将各种情况都考虑到,然后使用if-else语句将这些情况描述出来。

不过,在C语言程序开发中,滥用 if 语句常常会让整个代码变得啰嗦且不可读,C语言初学者小明也发现了这一点。下面是一段C语言代码示例,请看:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}
executeThisFunctionInAnyCase();
3d9b4b43651dd4b8a00560846eae601e.png

executeStepX() 函数只有在前一个函数执行结果为真时才会执行,而 executeThisFunctionInAnyCase() 函数则无论如何都会执行。小明觉得虽然这样写C语言代码可以实现需求,但是 if 语句链显然不是一种优雅的写法,他希望在自己的代码中避免 if 语句链出现,因此尝试对上述C语言代码做了如下修改,请看:
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
0ef454e30876f58af8523730eb4e8260.png

修改后的C语言代码看起来简洁多了,但是却不能满足需求——原先 executeThisFunctionInAnyCase() 函数无论如何都会执行,而现在它只会在 executeStepX() 函数都成功才会执行。

怎样才能避免 if 语句链,并且完美实现小明的需求呢?

按照小明的思路,其实只要保证 executeThisFunctionInAnyCase() 函数无论如何都被执行就可以了,那完全可以多定义一个函数解决这个问题,相关的C语言代码如下,请看:

void foo()
{
  bool conditionA = executeStepA();
  if (!conditionA) return;

  bool conditionB = executeStepB();
  if (!conditionB) return;

  bool conditionC = executeStepC();
  if (!conditionC) return;
}

void bar()
{
  foo();
  executeThisFunctionInAnyCase();
}
dcaec1a8de68247128cb1a034a448c3d.png

这样就按照小明的思路解决了问题。当然了,问题的答案不止一个,另外一种非常推荐的做法是使用“短路表达式”,相关的C语言代码如下,请看:

关于“短路表达式”的概念,可以参考我之前的文章《》;

if (executeStepA() && executeStepB() && executeStepC()){
    ...
}
executeThisFunctionInAnyCase();
c1451fd2440ceef084b772a947f6c5ed.png

C语言程序的“短路表达式”决定了只有 executeStepA() 函数成功才会接着执行 executeStepB() 函数,只有 executeStepB() 函数也成功,才会执行 executeStepC() 函数。而无论如何,executeThisFunctionInAnyCase() 函数都会被执行,这样就以较为简洁的方式解决了小明遇到的问题。

另外,还有一种很多C语言程序员都鄙视的方法——使用 goto 语句。我知道很多学校很多教材都非常抵制 goto 语句的“使用”,这里的“使用”打上了引号,是因为我认为他们反对的应该是 goto 语句的滥用,事实上,恰当的使用 goto 语句能够在很多时候简化C语言代码,例如:

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanup;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    executeThisFunctionInAnyCase();
    return result;
}
fb50cc1eac50c4517ea3b5ee1e6c0e8a.png

这样的代码风格在 Linux 内核代码中相当常见。也有些程序员习惯使用 do{}while(0) 包裹代码,并且通过 break 关键字提前跳出代码块,但实际上两种方法是一致的。如果还有其他的一些工作需要处理,goto 语句更方便,例如:
int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanupPart;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    innerCleanup();
cleanupPart:
    executeThisFunctionInAnyCase();
    return result;
}
76f5d12603aafeb6a66d1f777321c4fe.png

这种情况下如果使用 do{}while(0) 方法,就需要使用不止一个循环体,要是如此类推下去,循环体本身也会带来代码复杂度,这样的技巧就显得有些鸡肋了。

本节通过一个例子,简要的讨论了在C语言代码中避免 if 语句链的几种常用方法。当然了,本节只是抛砖引玉,相信读者肯定也有自己的技巧,欢迎在评论区讨论。同时,我们也能看出,C语言程序开发并不只是使用计算机语言描述“流水账”,多思考,总是能写出更加简洁优雅的代码的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK