b&&0可以优化吗
Can b&&0 be optimized
我知道C/C++使用短路计算来计算布尔表达式。例如,C/C++肯定会在表达式a && b
中的操作数b
之前计算操作数a
,如果a
为假,b
不会被评价。
此外,我知道 5==6
之类的东西可能会被编译器完全忽略,因为它是一个常量表达式,可以在编译时求值。
但是不知道b && 0
能不能被编译器优化?编译器可以说:好的,0
的计算比 b
的计算容易得多,而且 b
没有任何副作用,所以我决定更改 b && 0
进入 0 && b
以首先评估 0
。
你的问题涉及两个独立的问题。第一个是,当编译器“看到”if
条件总是 false
(由于 && 0
)时,它可以完全丢弃相应的分支。示例翻译单元:
bool f(int);
int main()
{
if (f(1) && 0)
return 1;
}
启用优化后,很可能不会为分支生成机器代码。但是,f(1)
表达式仍必须在运行时进行计算,因为编译器无法证明 f(1)
调用没有可观察到的行为。
机器码:https://godbolt.org/z/sEMrfh
相反,如果编译器能够证明f(1)
没有可观察到的行为,它就可以消除它的调用。这与评估顺序无关,而是与 as-if 规则有关。演示翻译单元:
static bool f(int i)
{
int j = i + 1;
return true;
}
int main()
{
if (f(1) && 0)
return 1;
}
&&
和 ||
运算符保证从左到右求值。评估意味着编译器必须检查操作数的副作用,如果存在副作用,则必须执行这些副作用。如果 &&
的左操作数计算为零,则不会计算右操作数。
考虑if(func() && 0) { do_stuff(); }
。即使 &&
表达式永远不会为真,函数仍然必须执行。编译器不会做一些奇怪的重新排序,例如 0 && func()
,它只会用 func();
替换整个表达式,删除 if
和 do_stuff()
.
一般来说,编译器明确不允许对&&
和||
的操作数的求值或执行进行重新排序;他们在左右操作数的求值之间有一个所谓的序列点。这反过来又允许像 (ptr=malloc(...)) && (*ptr = x)
这样的代码定义明确,并且在 malloc
失败的情况下不访问空指针。
我知道C/C++使用短路计算来计算布尔表达式。例如,C/C++肯定会在表达式a && b
中的操作数b
之前计算操作数a
,如果a
为假,b
不会被评价。
此外,我知道 5==6
之类的东西可能会被编译器完全忽略,因为它是一个常量表达式,可以在编译时求值。
但是不知道b && 0
能不能被编译器优化?编译器可以说:好的,0
的计算比 b
的计算容易得多,而且 b
没有任何副作用,所以我决定更改 b && 0
进入 0 && b
以首先评估 0
。
你的问题涉及两个独立的问题。第一个是,当编译器“看到”if
条件总是 false
(由于 && 0
)时,它可以完全丢弃相应的分支。示例翻译单元:
bool f(int);
int main()
{
if (f(1) && 0)
return 1;
}
启用优化后,很可能不会为分支生成机器代码。但是,f(1)
表达式仍必须在运行时进行计算,因为编译器无法证明 f(1)
调用没有可观察到的行为。
机器码:https://godbolt.org/z/sEMrfh
相反,如果编译器能够证明f(1)
没有可观察到的行为,它就可以消除它的调用。这与评估顺序无关,而是与 as-if 规则有关。演示翻译单元:
static bool f(int i)
{
int j = i + 1;
return true;
}
int main()
{
if (f(1) && 0)
return 1;
}
&&
和 ||
运算符保证从左到右求值。评估意味着编译器必须检查操作数的副作用,如果存在副作用,则必须执行这些副作用。如果 &&
的左操作数计算为零,则不会计算右操作数。
考虑if(func() && 0) { do_stuff(); }
。即使 &&
表达式永远不会为真,函数仍然必须执行。编译器不会做一些奇怪的重新排序,例如 0 && func()
,它只会用 func();
替换整个表达式,删除 if
和 do_stuff()
.
一般来说,编译器明确不允许对&&
和||
的操作数的求值或执行进行重新排序;他们在左右操作数的求值之间有一个所谓的序列点。这反过来又允许像 (ptr=malloc(...)) && (*ptr = x)
这样的代码定义明确,并且在 malloc
失败的情况下不访问空指针。