【问题标题】:Multiple If statements versus single statement with conditions evaluated using logical operators多个 If 语句与使用逻辑运算符评估条件的单个语句
【发布时间】:2020-02-23 15:27:31
【问题描述】:

我正在编写一个函数,在实际执行其任务之前检查几个条件。这是由许多if 语句完成的。像这样:

bool foo()
{
    if(invalid())
        return false;
    if(dont_execute())
        return false;
    // .. etc
    // Actual execution here
    return true;
}

在这个函数中,将多个条件更改为:

bool foo()
{
    if(invalid() || dont_execute() /* || .. etc */)
        return false;
    // Actual execution here
    return true;
}

我觉得第一种风格更具可读性。我想知道的是,使用多个 if 语句而不是使用逻辑运算符组合是否会对性能产生影响。

【问题讨论】:

  • 你对比过编译器生成的程序集吗?甚至有区别吗?你可以和godbolt.org比较一下
  • 我总是选择可读性而不是性能,除非且仅当性能是最重要的因素

标签: c++ performance if-statement logical-operators


【解决方案1】:

不,没有性能影响。如果我们 compare the assembly 两个函数,我们可以看到这两个函数是相同的。

例子:

bool f1();
bool f2();

bool combined()
{
    if (f1() || f2())
        return false;

    return true;
}

bool separate()
{
    if (f1())
        return false;

    if (f2())
        return false;

    return true;
}

这里是大会:

combined():
        sub     rsp, 8
        call    f1()
        mov     r8d, eax
        xor     eax, eax
        test    r8b, r8b
        jne     .L1
        call    f2()
        xor     eax, 1
.L1:
        add     rsp, 8
        ret

separate():
        sub     rsp, 8
        call    f1()
        mov     r8d, eax
        xor     eax, eax
        test    r8b, r8b
        jne     .L7
        call    f2()
        xor     eax, 1
.L7:
        add     rsp, 8
        ret

【讨论】:

    【解决方案2】:

    使用测试用例

    bool invalid();
    
    bool dont_execute();
    
    void execute();
    
    bool foo()
    {
        if(invalid())
            return false;
        if(dont_execute())
            return false;
        execute();
        return true;
    }
    
    bool foo2()
    {
        if(invalid() || dont_execute() /* || .. etc */)
            return false;
        execute();
        return true;
    }
    

    您可以看到foofoo2 都被带有-O2 优化标志的GCC 9.2 和Clang 9 编译为完全相同的程序集,请参阅godbolt。例如 GCC 的输出是

    foo():
            sub     rsp, 8
            call    invalid()
            test    al, al
            je      .L2
    .L4:
            xor     eax, eax
            add     rsp, 8
            ret
    .L2:
            call    dont_execute()
            test    al, al
            jne     .L4
            call    execute()
            mov     eax, 1
            add     rsp, 8
            ret
    foo2():
            sub     rsp, 8
            call    invalid()
            test    al, al
            je      .L8
    .L10:
            xor     eax, eax
            add     rsp, 8
            ret
    .L8:
            call    dont_execute()
            test    al, al
            jne     .L10
            call    execute()
            mov     eax, 1
            add     rsp, 8
            ret
    

    虽然这并不意味着永远不会有区别,但至少编译器认为他们不需要在这两种情况下做任何不同的事情,即使他们不知道什么调用的函数。

    所以我建议你不要担心性能,而是选择你认为更具可读性的东西。

    【讨论】:

      猜你喜欢
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 2013-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多