ChatGPT解决这个技术问题 Extra ChatGPT

为什么这个结合赋值和相等检查的 if 语句返回 true?

我一直在考虑一些初学者的错误,最后我发现了 if 语句中的错误。我将代码扩展为:

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

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

伙计们,这不是一个拼写错误的问题。 OP 想知道为什么使用此代码输入 if 语句,因为 i 设置为 1
还是它分配 1 && i == 0 的结果?
给初学者的建议:他们不应该使用这种“高级”的语言结构。只需单独分配变量。这也将避免序列点可能出现的问题。实际代码中的这种代码通常看起来也很糟糕。
这肯定会以面试问题告终

s
syck

这与 operator precedence 有关。

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

不是

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

因为 &&== 的优先级都高于 =。它真正起作用的是

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

它将 1 && (i == 0) 的结果分配给 i。因此,如果 i0 开始,则 i == 0true,所以 1 && truetrue(或 1),然后 i 设置为 1。然后由于 1 为真,您输入 if 块并打印您分配给 i 的值。


@JörgWMittag 这很酷。我喜欢它强迫你使用括号。
基本上,i = !i; if (i) 写得正确
@NathanOliver:Fortress 是一种非常酷的语言,它把很多事情都做对了。 (首席设计师是 Guy L. Steele,所以这并不奇怪。)不幸的是,它没有在 DARPA 的最后一轮资金中被选中,随后被甲骨文封存。
自然,向编译器请求少量警告就会检测到该错误,
任何不假定 int 和 booleans 是等价的语言也会选择这个。
佚名

假设您的代码实际上如下所示:

#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
有额外的代码 - 但它仍然不是不正确的代码。答案仍然是正确的。当然,它并没有解释运算符的优先级。但是有人可能会建议添加它,而不是直接投反对票!
哇,-4 很苛刻,考虑到这正确地回答了这个问题,尽管可能不是最佳的。它没有像其他答案那样扩展运算符优先级,但它确实在代码上下文中说明了足够多的内容,因此任何认为 = 出现在 && 之前的人都可以看到这个问题。另外,是的,扩展是无关紧要的,但我认为这并不重要。我无法相信如此细微的差异会导致人们以 151 票对 -4 票进行投票。
a
ar18

实际答案是:

编译器优先考虑“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 使用任何在线编译器亲自查看


1) 当这个问题用 C++ 标记时,文档链接到 C 运算符优先级。两种不同的语言。 2a) i = 1 是一个赋值 [不是等价] 运算符; 2b) 我可以向您保证,if (i = 0) 在 C 和 C++ 中都将评估为错误条件,因此它是否评估为 true wrt wrt “它永远不会失败”有点误导。
and cl, 1 ; = operator always TRUE <<如果我错了,请纠正我,但我在这里看不到任何分配。它表示表达式的 1 && 部分。所以这个答案基本上评估为 false
“当这个问题用 C++ 标记时,文档链接到 C 运算符优先级。两种不同的语言”——当您将 C 与 C++ 运算符优先级进行比较时,两者之间有什么区别?他们在这个话题上具有相同的优先级,这并不奇怪,因为 C++ 是 C 的直接派生(或者换一种说法,C 是 C++ 语言的子集,所以他们当然会有很多共同点,包括优先级)。无论如何,我会修复我的帖子,以防令人困惑。
“如果我错了,请纠正我,但我在这里看不到任何分配”——然后让我纠正你! 1 是一个立即值,而不是任何测试或计算的结果。这就是所谓的“假定的 TRUE”值。唯一发生的测试是针对 i==0 语句,即——“cmp dword ptr [rbp - 8], 0”。只有当它说“movzx edx,1”时你才是正确的。根据我之前的所有帖子,应该有两个比较,但在现实生活中只有一个,每个主要编译器的 asm 输出都证明这些帖子完全不正确。
除了优先级错误(请参阅 NathanOliver 的正确解析答案),您还错误地声称赋值运算符始终评估为 TRUE。试试 if ( i = 0 ) { print something }。您的回答也自相矛盾;在开始时您说在应用 && 之前评估 i=1,然后在最后您说 i 设置为 && 运算符的结果。
L
Leslie Satenstein

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

我感觉合理。


关联性(“从右到左的规则”)与此无关。这是关于优先级(“重要性”),并且使用的运算符没有相同的优先级。