为什么Linux内核使用双重逻辑取反而不是强制转换?

时间:2018-07-06 23:10:47

标签: c casting negation

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

int y = !!x;

这是我想发生的情况:x被隐式转换为bool,并执行第一个否定,之后进行最后一个否定,因此进行了一次转换和两个否定。

我的问题是,不仅仅是保存布尔值(执行int y = (bool)x;而不是int y = !!x)要比使用双重否定更快,因为您要保存两个否定执行。

我可能是错的,因为我在Linux内核中经常看到双重否定,但是我不明白我的直觉出了什么问题,也许您可​​以帮帮我。

3 个答案:

答案 0 :(得分:9)

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

附录:根据C89 draft standardsection 3.3.3.3

  

逻辑否定运算符的结果!如果其操作数的值比较不等于0,则为0;如果其操作数的值比较等于0,则为1。结果的类型为int。表达式!E等效于(0 == E)。

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

答案 1 :(得分:1)

  

我能想象的唯一原因是因为这样可以节省一些键入(7个字符对2个字符)。

正如@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

答案 2 :(得分:1)

C语言与其他语言不同,没有bool类型。 bool中的C实际上是在stdbool.h中定义的,许多项目C中没有包含。 Linux内核就是这样的一个项目,现在遍历Linux代码并更新所有内容以使用bool会很痛苦。这就是Linux内核不使用bool中的C的原因。

为什么!!x?这样做是为了确保y的值是10。例如,如果您有此密码

x=5;
int y = !!x;

我们知道C中非零值表示真的一切。因此,上面的代码会刹车到y= !!(5),然后是y = !(0),然后是y = 1

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

编辑2: 为了进一步说明,在您输入C++时,您可以使用Javabool a = false和其他语言,而不必使用标头或编译其他库或为{{ 1}}类型才能正常工作,它已经被合并到编译器中,就像在c中一样。

编辑3: boolbool不同。