Несколько операторов If против одного оператора с условиями, оцененными с использованием логических операторов - PullRequest
1 голос
/ 23 февраля 2020

Я пишу функцию, которая проверяет несколько условий, прежде чем фактически выполнить свою задачу. Это делается с помощью ряда 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 вместо комбинирования с использованием логических операторов.

Ответы [ 2 ]

4 голосов
/ 23 февраля 2020

Нет, это не влияет на производительность. Если мы сравним сборку обеих функций, мы увидим, что она идентична для обеих функций.

Пример:

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 голосов
/ 23 февраля 2020

Используя контрольный пример

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;
}

, вы можете увидеть, что и foo, и foo2 скомпилированы в одну и ту же сборку как G CC 9.2, так и Clang 9 с оптимизацией -O2 флаги см. Годболт . Например, вывод G CC равен

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

Хотя это не означает, что никогда не будет разницы, по крайней мере компиляторы не думают, что они должны это делать что-то различное в этих двух случаях, даже если они не знают, что делают вызываемые функции.

Поэтому я предлагаю вам не беспокоиться о производительности, а go о том, что вы считаете более читабельным.

...