Компиляторам разрешено предполагать, что базовое значение bool
не испорчено, поэтому оптимизирующие компиляторы могут избежать ветвления.
Если мы посмотрим на сгенерированный код для этого искусственного теста
int with_if_bool(bool a, int b) {
if(a){b++;}
return b;
}
int with_if_char(unsigned char a, int b) {
if(a){b++;}
return b;
}
int without_if(bool a, int b) {
b += a;
return b;
}
clang воспользуется этим фактом и сгенерирует точно такой же код без ветвей, который суммирует a
и b
для версии bool
, и вместо этого сгенерирует фактическое сравнение с нулем в случае unsigned char
(хотя это все еще код без ветвей ):
with_if_bool(bool, int): # @with_if_bool(bool, int)
lea eax, [rdi + rsi]
ret
with_if_char(unsigned char, int): # @with_if_char(unsigned char, int)
cmp dil, 1
sbb esi, -1
mov eax, esi
ret
without_if(bool, int): # @without_if(bool, int)
lea eax, [rdi + rsi]
ret
gcc вместо этого будет обрабатывать bool
, как если бы это был unsigned char
, без использования его свойств, генерируя код, аналогичный unsigned char
случаю clang.
with_if_bool(bool, int):
mov eax, esi
cmp dil, 1
sbb eax, -1
ret
with_if_char(unsigned char, int):
mov eax, esi
cmp dil, 1
sbb eax, -1
ret
without_if(bool, int):
movzx edi, dil
lea eax, [rdi+rsi]
ret
Наконец, Visual C ++ будет обрабатывать версии bool
и unsigned char
одинаково, точно так же, как gcc, хотя и с более наивным кодовым кодом (он использует условное перемещение вместо выполнения арифметики с регистром флагов, который IIRC традиционно использовал для быть менее эффективным, не знаю, для нынешних машин).
a$ = 8
b$ = 16
int with_if_bool(bool,int) PROC ; with_if_bool, COMDAT
test cl, cl
lea eax, DWORD PTR [rdx+1]
cmove eax, edx
ret 0
int with_if_bool(bool,int) ENDP ; with_if_bool
a$ = 8
b$ = 16
int with_if_char(unsigned char,int) PROC ; with_if_char, COMDAT
test cl, cl
lea eax, DWORD PTR [rdx+1]
cmove eax, edx
ret 0
int with_if_char(unsigned char,int) ENDP ; with_if_char
a$ = 8
b$ = 16
int without_if(bool,int) PROC ; without_if, COMDAT
movzx eax, cl
add eax, edx
ret 0
int without_if(bool,int) ENDP ; without_if
Во всех случаях ветви не создаются; единственное отличие состоит в том, что на большинстве компиляторов генерируется более сложный код, который зависит от cmp
или test
, создавая более длинную цепочку зависимостей.
При этом я буду беспокоиться об этом виде микрооптимизации, только если вы фактически запустите свой код под профилировщиком, и результаты указывают на этот конкретный код (или на какой-то жесткий цикл, который его задействует); в общем, вы должны написать разумный, семантически правильный код и сосредоточиться на использовании правильных алгоритмов / структур данных. Микрооптимизация наступит позже.
В моей программе это не сработает, так как на самом деле это операция типа: b+=(a==c)
Это должно быть еще лучше для оптимизатора, так как у него даже нет никаких сомнений относительно того, откуда берется bool
- он может просто принять решение прямо из регистра флагов. Как вы можете видеть , здесь gcc выдает довольно схожий код для двух случаев, clang точно такой же, в то время как VC ++, как обычно, выдает нечто более условное (cmov
) в if
случай.