Зачем использовать!!(условие) вместо (условие)?
Я видел код, где люди использовали условные предложения с двумя '!'
#define check_bit(var, pos) (!!((var) & (1 << (pos))))
#define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)
Вот некоторые примеры, которые я смог найти.
Есть ли преимущество в использовании !!(condition)
над (condition)
?
4 ответа
Хорошо, если переменная, которую вы применяете !!
это уже не bool
(либо ноль, либо единица), тогда оно нормализует значение либо 0
или же 1
,
Что касается __builtin_expect
Этот поток новичков ядра обсуждает нотацию и один из ответов объясняет (выделение мое):
Подпись __builtin_expect
http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) это:
long __builtin_expect (long exp, long c)
Обратите внимание, что параметр exp должен быть интегральным выражением, поэтому там нет указателей или типов с плавающей точкой. Двойное отрицание обрабатывает преобразование этих типов в целочисленные выражения автоматически. Таким образом, вы можете просто написать: вероятный (ptr) вместо вероятного (ptr! = NULL).
Для справки в С99 bool
макрос расширяется до _Bool
, true
расширяется до 1
а также false
расширяется до 0
, Подробности приведены в разделе проекта стандарта 7.16
Логический тип и значения.
Логическое отрицание кроется в 6.5.3.3
Унарные арифметические операторы в пункте 5:
Результат оператора логического отрицания! равен 0, если значение его операнда сравнивается с 0, 1, если значение его операнда сравнивается равным 0. Результат имеет тип int. Выражение!E эквивалентно (0==E).
Одинарный !
Оператор логического отрицания, примененный к любому скаляру, дает int
значение 0
если его операнд не равен нулю, 1
если операнд равен нулю. Цитируя стандарт:
Выражение
!E
эквивалентно(0==E)
,
применение !
дважды к одному и тому же скалярному значению выдает результат, который равен false, если значение равно false, true, если значение равно true, но результат нормализуется до 0
или же 1
соответственно.
В большинстве случаев в этом нет необходимости, поскольку любое скалярное значение можно использовать непосредственно как условие. Но в некоторых случаях вам действительно нужно 0
или же 1
значение.
В C99 или позже, приведение выражения к _Bool
(или для bool
если у вас есть #include <stdbool.h>
ведет себя аналогично и может считаться более понятным. Но (а) результат имеет тип _Bool
скорее, чем int
и (b) если вы используете компилятор до C99, который не поддерживает _Bool
и вы определили свой bool
типа, он не будет вести себя так же, как С99 _Bool
,
Самое большое, что я могу видеть, это то, что это заставит (или нормализует) значение в 1
или же 0
(это логическое значение) независимо от того, как x
или же var
выражение расширяется (например, char
или же double
или же int
или т. д.).
Он приводится к логическому значению, которое иногда может быть полезным.