Почему ядро ​​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
Другие вопросы по тегам