为什么 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..-1
和 1..INT_MAX
范围内的任何位模式都会产生 1,而零位模式是不言自明的。
C
语言不像其他语言那样没有 bool
类型。 C
中的bool
实际上是在stdbool.h
中定义的,许多C
项目中没有包含。 Linux 内核就是这样的一个项目,通过 Linux 代码并更新所有内容以现在也使用 bool
会很痛苦。这就是为什么 Linux 内核在 C
.
中不使用 bool
的原因
为什么 !!x
?这样做是为了确保 y
的值是 1
或 0
。例如,如果你有这个 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 或编译其他一些库或定义 bool
为 bool
类型工作的类型,它已经被合并到编译器中,而在 c 中你必须这样做。
编辑 3:
bool
与 _Bool
不同。
鉴于 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..-1
和 1..INT_MAX
范围内的任何位模式都会产生 1,而零位模式是不言自明的。
C
语言不像其他语言那样没有 bool
类型。 C
中的bool
实际上是在stdbool.h
中定义的,许多C
项目中没有包含。 Linux 内核就是这样的一个项目,通过 Linux 代码并更新所有内容以现在也使用 bool
会很痛苦。这就是为什么 Linux 内核在 C
.
bool
的原因
为什么 !!x
?这样做是为了确保 y
的值是 1
或 0
。例如,如果你有这个 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 或编译其他一些库或定义 bool
为 bool
类型工作的类型,它已经被合并到编译器中,而在 c 中你必须这样做。
编辑 3:
bool
与 _Bool
不同。