我一直在考虑一些初学者的错误,最后我发现了 if
语句中的错误。我将代码扩展为:
int i = 0;
if (i = 1 && i == 0) {
std::cout << i;
}
我已经看到 if
语句返回 true,并且它 cout
的 i
为 1
。如果在 if 语句中将 i
赋值为 1
,为什么 i == 0
返回 true
?
i
设置为 1
。
1 && i == 0
的结果?
这与 operator precedence 有关。
if (i = 1 && i == 0)
不是
if ((i = 1) && (i == 0))
因为 &&
和 ==
的优先级都高于 =
。它真正起作用的是
if (i = (1 && (i == 0)))
它将 1 && (i == 0)
的结果分配给 i
。因此,如果 i
从 0
开始,则 i == 0
是 true
,所以 1 && true
是 true
(或 1
),然后 i
设置为 1
。然后由于 1
为真,您输入 if 块并打印您分配给 i
的值。
假设您的代码实际上如下所示:
#include <iostream>
using namespace std;
int main() {
int i = 0;
if (i = 1 && i == 0) {
cout << i;
}
}
然后这个:
if (i = 1 && i == 0) {
评估为
if (i = (1 && i == 0)) {
因此 i
设置为 1
。
using namespace std
!
=
出现在 &&
之前的人都可以看到这个问题。另外,是的,扩展是无关紧要的,但我认为这并不重要。我无法相信如此细微的差异会导致人们以 151 票对 -4 票进行投票。
实际答案是:
编译器优先考虑“i == 0”,其计算结果为真。然后它将 i=1 评估为 TRUE 或 FALSE,并且由于编译的赋值运算符永远不会失败(否则它们不会编译),它也评估为 true。由于两个语句都评估为真,并且 TRUE && TRUE 评估为 TRUE,因此 if 语句将评估为 TRUE。
作为证明,只需查看您输入的代码的编译器的 asm 输出(所有注释都是我自己的):
mov dword ptr [rbp - 8], 0 ; i = 0;
cmp dword ptr [rbp - 8], 0 ; i == 0?
sete al ; TRUE (=1)
mov cl, al
and cl, 1 ; = operator always TRUE
movzx edx, cl
mov dword ptr [rbp - 8], edx ; set i=TRUE;
test al, 1 ; al never changed,
; so final ans is TRUE
上面的 asm 输出来自 CLANG,但我查看的所有其他编译器都给出了类似的输出。对于该站点上的所有编译器都是如此,无论它们是纯 C 还是 C++ 编译器,都没有任何 pragma 来更改编译器的模式(对于 C++ 编译器,默认情况下是 C++)
请注意,您的编译器实际上并没有设置 i=1,而是 i=TRUE(这意味着任何 32 位非零整数值)。那是因为 &&运算符仅评估语句是 TRUE 还是 FALSE,然后根据该结果设置结果。作为证明,尝试将 i=1 更改为 i=2,您可以自己观察到什么都不会改变。在 Compiler Explorer 使用任何在线编译器亲自查看
i = 1
是一个赋值 [不是等价] 运算符; 2b) 我可以向您保证,if (i = 0)
在 C 和 C++ 中都将评估为错误条件,因此它是否评估为 true wrt wrt “它永远不会失败”有点误导。
and cl, 1 ; = operator always TRUE
<<如果我错了,请纠正我,但我在这里看不到任何分配。它表示表达式的 1 &&
部分。所以这个答案基本上评估为 false
。
if ( i = 0 ) { print something }
。您的回答也自相矛盾;在开始时您说在应用 &&
之前评估 i=1
,然后在最后您说 i
设置为 &&
运算符的结果。
它与解析从右到左的规则有关。例如 y = x+5。所有子表达式都按重要性加权。两个同等重要的表达式从右到左求值, 。 && 表达式端首先完成,然后是 LHS。
我感觉合理。
i = !i; if (i)
写得正确