Зачем использовать (условие) вместо (условие)?

Я видел код, в котором люди использовали условные предложения с двумя "!"

#define check_bit(var, pos)       (!!((var) & (1 << (pos))))
#define likely(x)       __builtin_expect(!!(x),1)
#define unlikely(x)     __builtin_expect(!!(x),0)

- некоторые из примеров, которые я мог найти.

Есть ли преимущество в использовании !!(condition) над (condition)?

Ответ 1

Хорошо, если переменная, которую вы применяете !!, уже не является 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).

Для справки в C99 bool макрос расширяется до _Bool, true расширяется до 1 и false расширяется до 0. Подробности приведены в проекте стандартного раздела 7.16 Логический тип и значения.

Логическое отрицание рассматривается в 6.5.3.3 Унарных арифметических операторах в параграфе 5:

Результат оператора логического отрицания! 0, если значение его операнда сравнивается не равно 0, 1, если значение его операнда сравнивается с равным 0. Результат имеет тип int. Выражение! E эквивалентно (0 == E).

Ответ 2

Унарный оператор ! логического отрицания, применяемый к любому скаляру, дает значение int 0, если его операнд отличен от нуля, 1, если операнд равен нулю. Цитирование стандарта:

Выражение !E эквивалентно (0==E).

Применяя ! дважды к одному и тому же скалярному значению, получаем результат, если false, если значение ложно, true, если значение истинно, но результат нормализуется до 0 или 1 соответственно.

В большинстве случаев это необязательно, так как любое скалярное значение может использоваться непосредственно как условие. Но в некоторых случаях вам действительно нужно значение 0 или 1.

В C99 или более поздней версии выражение _Bool (или bool), если у вас есть #include <stdbool.h>, ведет себя аналогично и может считаться более ясным. Но (a) результат имеет тип _Bool, а не int и (b) если вы используете компилятор pre-C99, который не поддерживает _Bool, и вы определили свой собственный тип bool, он не будет вести себя так же, как C99 _Bool.

Ответ 3

Самый большой, что я вижу, заключается в том, что он будет принудительно (или нормализовать) значение в 1 или 0 (это логическое значение) независимо от того, как выражение x или var расширяется (например, char или double или int или т.д.).

Ответ 4

Он ссылается на логическое значение, которое иногда может быть полезно.