2015-01-27 2 views
-1

Я пытаюсь оценить, если есть падение производительности в письменной форме этого выраженияразбивая условное выражение

bool func() { 
    if (expr1 || expr2 ... || exprN) 
     return 1; 
    return 0; 
} 

в

bool func() { 

    if (expr1) 
     return 1; 

    if (expr2) 
     return 1; 

    ... 

    if (exprN) 
     return 1; 

    return 0; 
} 

Причины я пытаюсь сделать последнее просто улучшить читаемость/ремонтопригодность (например, последняя может быть записана с помощью вспомогательного макроса и тем самым упростить добавление/удаление expr. В этом случае около 50 выражений).

Подобный сценарий пишет

bool func() { 
    if (expr1 && expr2 && ... && exprN) { 
     return 1; 
    } 

    return 0; 
} 

в

bool func() { 
    if (!expr1) { 
     return 0; 
    } 

    if (!expr2) { 
     return 0; 
    } 

    ... 

    if (!exprN) { 
     return 0; 
    } 

    return 1; 
} 

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

(Чтобы дать некоторый контекст выражения сами являются функциями и предположим, что мы хотим, чтобы определить, все или, по крайней мере, один возвращает истину. Функции принимают аргументы различных типов)

+1

Распечатайте список языков ассемблера, сгенерированный компилятором. Между кодом, созданным вашими примерами, не должно быть разницы. –

+0

Вы должны поместить все 'expr1 || expr2' ... и т. д. в другую функцию. –

+1

Больше читать не соответствует лучшей читаемости. И ваши первые два кодовых блока не выглядят эквивалентными. – Deduplicator

ответ

2

Ваши две версии функционально эквивалентны.

В C/C++ (и многих других языках) логические операторы || и && выполняют "short-circuit" evaluation. Они оценивают подвыражения слева направо, останавливаясь, как только результат известен. В случае || это означает, что он останавливается, как только он получает истинное (отличное от нуля) результат (потому что true || anything истинно); в случае && он останавливается, как только он получает результат с ложным (нулевым) (потому что false && anything является ложным).

Если вы выполняли какие-либо другие действия в своих телах if, кроме как только возвращались из функции, это было бы дублировано для каждого выражения, которое является истинным. Но поскольку вы возвращаетесь из функции, как только одно из выражений истинно, вы никогда не будете проверять какое-либо из оставшихся выражений. Таким образом, он делает то же короткое замыкание.

Если у вас есть какое-то действие в теле, вы можете получить тот же тип короткого замыкания, используя else if, а не if. Однако это нарушит принцип DRY. Но если это результат макроса, а не исходного исходного кода, это не будет серьезной проблемой (хотя, скорее всего, это увеличит размер сгенерированного кода - если принять его в крайности, это может иметь последствия для производительности памяти) ,

0

Коды C и C++ генерируются в соответствии с его эквивалентом сборки. Следовательно, я думаю, что созданный код не должен отличаться, если у вас нет нескольких функций вывода или операторов перехода (включая Return, как и в вашем втором примере). Так что я думаю, что не должно быть никакого удара производительности, если у вас слишком много переходов в вашем улучшенном коде чтения.

1

Вашего текущий код

bool func() { 
    if (expr1 || expr2 ... || exprN) 
     return 1; 
    return 0; 
} 

с участием многочисленных логических выражений, можно записать, как, возможно, более ясно & ремонтопригодны

auto func() 
    -> bool 
{ 
    return false 
     || expr1 
     || expr2 ... 
     || exprN; 
} 

Это позволяет компилятор лучшая возможности для оптимизации, так как оно представлено с полную информацию о желаемом эффекте.

Напротив, ряд отдельных операторов if должен быть проанализирован компилятором, чтобы определить, что они реализуют OR-цепь.

Как всегда, если у вас возникли сомнения относительно микропроизводительности, MEASURE.

Смежные вопросы