Более эффективный оператор If / Else в C - PullRequest
0 голосов
/ 06 марта 2020

Мне было интересно, работают ли два разных кода ниже, чем другие. Они выполняют ту же функцию. Я думаю, что при реализации этого кода вы бы хотели, чтобы оператор if содержал аргумент, который встречался бы чаще.

Опция # 1

if(hoursWorked <= 40){
    workedOvertime = 0;
}
else{
    workedOvertime = 1;
}

Опция # 2

if(hoursWorked > 40){
    workedOvertime = 1;
}
else{
    workedOvertime = 0;
}

Ответы [ 2 ]

5 голосов
/ 06 марта 2020

В Godbolt Compiler Explorer вы можете увидеть, что различные компиляторы делают с обеими версиями, а также «вариант 3» KamilCuk.

Угадайте, что: например, с помощью g * Компилятор cc на x86-64 и оптимизация - все они выдают точно такой же код. Так что это не имеет никакого значения.

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

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

Если у вас есть основания полагать, что один случай более распространен, чем другой, вы можете использовать что-то вроде g cc __builtin_expect, чтобы намекнуть это компилятору. Таким образом, если есть возможность оптимизировать одну ветвь так, чтобы она была быстрее другой, компилятор сделает это для более общей. Также могут быть способы использовать профилирование для измерения того, какая ветвь используется чаще, и автоматически информировать об этом компилятор. Но компилятор обычно не будет пытаться сделать такие выводы только из вашего выбора, какая ветвь является «тогда», а какая «остальной».

Однако в этом случае использование __builtin_expect не делает Это ничего не меняет, поэтому обе ветви уже оптимизированы так, как это хорошо знает компилятор, и он не знает, как сделать одну из них быстрее, даже за счет замедления другой.

3 голосов
/ 06 марта 2020

Почти невозможно дать ответ на этот вопрос, так как это будет зависеть от архитектуры машины, компилятора, опций компилятора (например, оптимизации) и множества других вещей. Например, одна архитектура, над которой я работал, нам сказали, что условные выражения, использующие «not», были быстрее. Я не знаю, правда ли это, но if (hoursWorked <= 40) было бы написано if (!(hoursWorked > 40)). Я знаю: труднее читать, но это то, что нам было сказано!

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

Например, в ассемблере 68K "BEQ" (ветвь на равных) занимает 10 циклов, если условие выполнено, и 8 или 12, если его нет (в зависимости от используете ли вы байты или слова), так что это 3 возможных ответа только для «если» в зависимости от типов и того, каким образом идет код. Для сравнения, одно умножение занимает 70 циклов. Если вы доберетесь до IO, то мы, вероятно, исчисляемся тысячами (если не больше).

Так что, если у вас нет действительно веской причины заботиться о вещах на этом уровне, не делайте этого! Это пустая трата времени. Напишите хороший читаемый код, а затем вернитесь к этому, если и когда у вас возникнут проблемы с производительностью.

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

...