gcc 或其他编译器在条件表达式中使用时是否会自动将按位 or 转换为布尔值 or?

Does gcc or other compilers auto convert bitwise or's to boolean or's when used in conditional expressions?

本文关键字:or 布尔值 转换 是否 编译器 其他 条件 表达式 gcc      更新时间:2023-10-16

如果我有一个带有逻辑或运算符||的C语句:

if (isFoo() || isBar())
    blah();

如果isFoo()返回true,编译器生成的代码将不会执行isBar()

位或运算符|呢?

if (isFoo() | isBar())
    blah();

可能这是潦草的书写,或者如果作者要求 isBar() isFoo()因为这些函数的副作用而同时被执行,那么他们应该更清楚地表达他们的意图。或者我错了,这是一个可以接受的C/c++习语。

然而,一个体面的编译器实际上会生成一个临时变量来做isFoo()isBar()的返回值的按位或ing,当优化打开?或者它会将按位或操作转换为逻辑或操作,以便允许布尔表达式的短路,以防止调用isBar() ?

编译器可以随心所欲地优化"or'ing",但是程序必须表现得好像两个函数调用实际上都发生了,并且它们可以以的顺序发生。有一次,我天真地把||改成了|,因为我需要两个调用都发生,但我忘记了右调用可能发生在左调用之前,而右调用取决于左调用的结果……直到有人决定尝试用pcc而不是gcc编译我的代码,这个bug才出现。所以我的建议是要小心这样的东西,把你的意思写清楚。

最后,请注意我说的"好像两个函数调用实际上都发生了",因为在编译器可以确定函数没有副作用的情况下,如果左边的结果是非零值,它可能会优化右边。

"然而,一个好的编译器会生成一个临时的变量对isFoo()和isBar()当优化打开?"

是的。短路不适用于位运算符。

不,这不是一个合理的编码实践。除了||的短路和排序语义外,它执行的操作与|不同。

||如果其中一个操作数非零则返回1,如果两个操作数都为零则返回0。

|给出其操作数的按位

碰巧的是,结果的真值将是相同的(我在输入这个答案时意识到这一点)。但是考虑相应的&&&操作符。:

if (isFoo() && isBar())

当且仅当两个函数都返回非零值时为真,但是下面这个:

if (isFoo() & isBar())

当且仅当和的结果非零时为真。如果isFoo()返回1,isBar()返回2(结果均为真),则isFoo & isBar()将为0,或为false。

请注意,<ctype.h>中声明的is*()函数只指定为true时返回非零;它们可以并且确实返回0或1以外的值。

如果你真的想避免||的短路行为,把结果赋值给临时对象:

bool is_foo = isFoo();
bool is_bar = isBar();
if (is_foo && is_bar) ...

我们这里讲的是C语言所以我们必须有像

这样的东西
typedef int BOOL;
BOOL isFoo();
BOOL isBAr();

这是因为只有c++(而不是C)有布尔类型。

现在,当我们计算isFoo() || isBar()时,编译器知道,由于我们使用的是逻辑,或者如果isFoo()返回true,那么无论isBar()的值如何,整个语句的计算结果都将为true,因此编译器可以安全地短路' isBar() '。

然而,当我们计算isFoo() | isBar()时,我们实际上是在对两个整数进行环运算。编译器无法知道isFoo()和isBar()只能返回0或1,因此必须对两个表达式求值,因为即使isFoo()返回1,最终结果也可能是不同的(比如3)。

c++确实有一个bool类型,如果isFoo()isBar()返回bool s,编译器真的不需要计算isBar()。我不是c++规范方面的专家,但我认为,由于位运算符对bool类型没有意义,因此bool将被提升为int并相应地求值。