Почему ядро linux использует двойные логические отрицания вместо приведения к bools?
При условии x
переменная типа int
с номером 5
в качестве его значения рассмотрим следующее утверждение:
int y = !!x;
Вот что я думаю, что это происходит: x
неявно приведен к bool
и выполняется первое отрицание, после чего производится последнее отрицание, поэтому приведение и два отрицания.
У меня вопрос, а не просто приведение к bool (выполнение int y = (bool)x;
вместо int y = !!x
) быстрее, чем использование двойного отрицания, поскольку вы спасаете от выполнения два отрицания.
Я могу ошибаться, потому что я часто вижу двойное отрицание в ядре Linux, но я не понимаю, где моя интуиция идет не так, может быть, вы мне поможете.
3 ответа
На момент написания Linux не было типа bool. Язык C рассматривал все, что не было нулем, как истинное в булевых выражениях. Так что 7, -2 и 0xFF - все это "правда". Нет типа bool для приведения. Трюк с двойным отрицанием гарантирует, что результатом будет либо ноль, либо любой другой битовый шаблон, выбранный авторами компилятора для представления true в логических выражениях. Когда вы отлаживаете код и просматриваете значения памяти и регистра, легче распознать истинные значения, когда все они имеют одинаковые битовые комбинации.
Приложение: Согласно проекту стандарта С89, раздел 3.3.3.3:
Результат оператора логического отрицания! равен 0, если значение его операнда сравнивается с 0, 1, если значение его операнда сравнивается равным 0. Результат имеет тип int. Выражение!E эквивалентно (0==E).
Таким образом, хотя в первые годы существования ОС Linux не было никакого булева типа, двойное отрицание могло бы привести к 0 или 1 (спасибо Gox за указание на это), в зависимости от достоверности выражения. Другими словами, любой битовый паттерн в диапазоне INT_MIN..-1
а также 1..INT_MAX
дал бы 1, и нулевой битовый шаблон не требует пояснений.
C
язык в отличие от других языков не имеет bool
тип. bool
в C
на самом деле определяется в stdbool.h
который не входит во многие C
проекты. Ядро Linux является одним из таких проектов, было бы больно просматривать код Linux и обновлять все для использования bool
и сейчас. Вот почему ядро Linux не использует bool
в C
,
Зачем !!x
? Это сделано для того, чтобы обеспечить y
либо 1
или же 0
, Как пример, если у вас есть этот Cocd
x=5;
int y = !!x;
Мы знаем, что все, что ненулевые значения в C
значит правда. Таким образом, приведенный выше код будет тормозить до y= !!(5)
с последующим y = !(0)
и тогда y = 1
,
РЕДАКТИРОВАТЬ: Еще одна вещь, я только что видел, как OP упомянул кастинг на bool
, В C
здесь нет bool
как базовый тип, bool
это определенный тип, поэтому компиляторы не приводят целые числа к логическому типу.
РЕДАКТИРОВАТЬ 2: Для дальнейшего объяснения, в C++
, Java
и другие языки при вводе bool a = false
вам не нужно использовать заголовки или компилировать некоторые другие библиотеки или определить bool
тип для bool
Тип для работы, он уже включен в компиляторы, где, как в C вы должны.
РЕДАКТИРОВАТЬ 3:bool
это не то же самое, что _Bool
,
Единственная причина, которую я могу себе представить, заключается в том, что это экономит время при наборе текста (7 символов против 2 символов).
Как уже упоминали @jwdonahue и @Gox, это неверная причина. C не имел bool, когда было написано ядро linux, поэтому приведение к bool не было возможным.
Что касается эффективности, то оба они эквивалентны, потому что компиляторы могут легко понять это. Смотрите https://godbolt.org/g/ySo6K1
bool cast_to_bool_1(int x) {
return !!x;
}
bool cast_to_bool_2(int x) {
return (bool) x;
}
Обе функции компилируются в одну сборку, которая использует test
инструкция, чтобы проверить, является ли аргумент нулевым или нет.
test edi, edi // checks if the passed argument is 0 or not
setne al // set al to 0 or 1 based on the previous comparison
ret // returns the result