我一直在思考一些初学者的错误,最后我在if语句上犯了一个错误。我将代码扩展为:

int i = 0;
if (i = 1 && i == 0) {
    std::cout << i;
}

我已经看到if语句返回true,并且它将I计算为1。如果i在If语句中被赋值为1,为什么i == 0返回true?


当前回答

这与运算符优先级有关。

if (i = 1 && i == 0)

不是

if ((i = 1) && (i == 0))

因为&&和==的优先级都比=高。它真正的结果是

if (i = (1 && (i == 0)))

它将1 && (i == 0)的结果赋给i。因此,如果i从0开始,那么i == 0为真,因此1 && true为真(或1),然后i被设置为1。然后由于1为真,您进入if块并打印您分配给i的值。

其他回答

这与运算符优先级有关。

if (i = 1 && i == 0)

不是

if ((i = 1) && (i == 0))

因为&&和==的优先级都比=高。它真正的结果是

if (i = (1 && (i == 0)))

它将1 && (i == 0)的结果赋给i。因此,如果i从0开始,那么i == 0为真,因此1 && true为真(或1),然后i被设置为1。然后由于1为真,您进入if块并打印您分配给i的值。

实际的答案是:

编译器优先考虑"i == 0",其结果为true。 然后它将i=1计算为TRUE或FALSE,由于编译后的赋值操作符永远不会失败(否则它们不会编译),它也计算为TRUE。 由于这两个语句的值都为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++编译器,都没有任何改变编译器模式的pragmas(对于c++编译器,默认为c++)。

请注意,你的编译器实际上并没有设置i=1,而是i=TRUE(这意味着任何32位非零整数值)。这是因为&&操作符只计算语句是TRUE还是FALSE,然后根据该结果设置结果。作为证明,尝试将i=1更改为i=2,您可以自己观察到没有任何变化。在编译器资源管理器中使用任何在线编译器自行查看

假设你的代码是这样的:

#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。

它与解析从右到左的规则有关。 例如y = x+5。 所有子表达式都按重要性加权。 两个同等重要的表达式从右向左求值。首先完成&&表达式,然后是LHS。

对我来说很有道理。