为什么 linux 内核使用双重逻辑否定而不是强制转换为布尔值?

Why the linux kernel uses double logical negations instead of casts to bools?

鉴于 x 是一个 int 类型的变量,其值是数字 5,请考虑以下语句:

int y = !!x;

这就是我认为会发生的情况:x 被隐式转换为 bool 并执行第一个否定,然后执行最后一个否定,所以一个转换和两个否定。

我的问题是,不仅仅是强制转换为 bool(执行 int y = (bool)x; 而不是 int y = !!x)是否比使用双重否定更快,因为您正在执行两个否定。

我可能错了,因为我在 Linux 内核中经常看到双重否定,但我不明白我的直觉哪里出错了,也许你能帮我。

The only reason I can imagine is because this saves some typing (7 chars vs 2 chars).

正如@jwdonahue 和@Gox 已经提到的,这不是正确的原因。在编写 linux 内核时 C 没有 bool,因此转换为 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

最初写Linux的时候没有bool类型。 C 语言在布尔表达式中将所有不为零的都视为真。所以7、-2和0xFF都是"true"。没有要转换为的 bool 类型。双重否定技巧确保结果为零或编译器作者选择在布尔表达式中表示 true 的任何位模式。当您调试代码并查看内存和寄存器值时,如果它们都具有相同的位模式,则更容易识别真值。

附录:根据 C89 draft standard, section 3.3.3.3:

The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int . The expression !E is equivalent to (0==E).

因此,虽然 Linux OS 早期没有布尔类型,但双重否定会产生 0 或 1(感谢 Gox指出这一点),取决于表达的真实性。换句话说,INT_MIN..-11..INT_MAX 范围内的任何位模式都会产生 1,而零位模式是不言自明的。

C 语言不像其他语言那样没有 bool 类型。 C中的bool实际上是在stdbool.h中定义的,许多C项目中没有包含。 Linux 内核就是这样的一个项目,通过 Linux 代码并更新所有内容以现在也使用 bool 会很痛苦。这就是为什么 Linux 内核在 C.

中不使用 bool 的原因

为什么 !!x?这样做是为了确保 y 的值是 10。例如,如果你有这个 cocd

x=5;
int y = !!x;

我们知道 C 中 non-zero 值的所有值都为真。因此,上面的代码将分解为 y= !!(5),然后是 y = !(0),然后是 y = 1

编辑: 还有一件事,我刚刚看到 OP 提到转换为 bool。在 C 中没有 bool 作为基类型,bool 是定义类型,因此编译器不会将整数转换为布尔类型。

编辑 2: 进一步说明,在 C++Java 和其他语言中,当您键入 bool a = false 时,您不必使用 headers 或编译其他一些库或定义 boolbool 类型工作的类型,它已经被合并到编译器中,而在 c 中你必须这样做。

编辑 3: bool_Bool 不同。