C++运算符是如何工作的?

5

假设x=2,y=1,z=0,下面的语句会显示什么?

printf("answer = %d\n", (x || !y && z));

这是一道测验题,我答错了,我不记得我的教授讲过这个问题,请有人给我解释一下...我知道答案是1,但为什么呢?


5
以下语句将显示什么内容?"Go run it yourself... yikes. If you then don't understand and want to ask "why?", that's a reasonable question."去自己运行一下...呃。如果你还是不明白并想问“为什么?”,那就是个合理的问题。 - Tony Delroy
我知道,我做了,但这并不能向我解释操作背后的逻辑:/ - mayotic
可能是重复的:https://dev59.com/ek_Ta4cB1Zd3GeqPA3NU - jweyrich
5个回答

3
该表达式被解释为x || (!y &&z)(查看运算符||!&&的优先级)。 ||是一种短路运算符。如果左操作数为true(在||的情况下),则无需评估右侧操作数。
在您的情况下,x为true,因此作为布尔表达式的结果将为1。
编辑。
保证从左到右评估&&||的顺序。

2
短路布尔运算指的是如果左侧值足以确定整个表达式的真实性,则根本不会评估右侧值。这既是一种优化,也是在检查左侧指针不为空时,然后在右侧对其进行解引用时必不可少的。对于|| - 或运算符 - 如果左侧值为真,则整个表达式为真,并且右侧部分未评估。 - Tony Delroy
1
@Tony:右侧部分是否被评估是无关紧要的,因为它没有副作用。重要的是&&||具有更高的优先级(即绑定更紧密)。 - R.. GitHub STOP HELPING ICE
@R:只是回答了thrgle的一般问题...没有意图与问题中的表达相关。顺便说一句,扮演魔鬼的代言人 - 每个人都假定x、y、z的行为像内置类型一样:可能有一个operator=(X)用于某些数值类型X,但是operator bool() const或类似的操作符并不直观。不过,问题标记为C++和C,所以可以忽略C++的用户定义类型能力... :-) - Tony Delroy
那么 'int main(){ int x = 0, n = 0;bool b = ++x || (++n); cout << n;}' 的输出应该是什么? - Chubsdad
哦,好的。那就是困扰我的问题。现在没事了。 - Chubsdad
显示剩余7条评论

1

如果我没有弄错的话,它将打印1。(假设短路是关闭的)

(x || !y && z)(true || !true && false) 将先计算 ! 运算符,得到 (true || false && false)

然后是 &&: (true || false)

然后是 || :true

Printf 将十进制中的 true 解释为 1。所以它将打印 answer = 1\n


1
! 不会首先被计算!x 会被计算。 - Jonathan Leffler
3
错误 - 请参考Prasoon的答案并考虑短路求值。 - Tony Delroy
请注意,我说假设没有短路。但除此之外,你是正确的。我认为他可能想要一个更全面的答案。 - JoshD
4
如果你的编译器允许禁用短路运算,请删除它。 - jweyrich
@jweyrich:确实,我会把它删除。我的目的是向学习者说明运算顺序。 - JoshD

0
假设x = 2,y = 1,z = 0,下面的语句会显示什么? printf("answer = %d\n", (x || !y && z));
好的 - 对于问题的措辞不太好,我感到有点内疚,所以我会尝试以不同于其他答案的方式来帮助你... :-)
当你遇到这样的问题时,将其分解成可管理的部分。
试试:
int x = 2, y = 1, z = 0;

printf("true == %d\n", 10 > 2);                 // prints "1"
printf("false == %d\n", 1 == 2);                // prints "0"
printf("!y == %d\n", !y);                       // prints "0"
printf("(x || !y) == %d\n", x || !y);           // "1" - SEE COMMENTS BELOW
printf("(!y || z) == %d\n", !y || z);           // "0"
printf("(x || !y && z) == %d\n", x || !y && z); // "1"

在那里的输出中,你拥有了一切你需要去“推断”正在发生的事情:
  • true == 1 揭示了 C/C++ 如何将真实的布尔表达式转换为整数值 1,以便在 printf 中使用,而不考虑布尔表达式中出现的值。
  • false == 0 揭示了 C/C++ 如何将 false 表达式转换为“0”。
  • (!y) == 0 因为 ! 是逻辑非运算符,C/C++ 认为 0 是唯一对应 false 的整数值,而所有其他值都是 true,所以 !1 == !true == false == 0
  • (x || !y) == 1,你知道 !y 是 0,所以替换已知值并简化:(2 || 0) == 1 等价于 (true or false) == true...这是一个可理解的逻辑规则
  • (!y || z) == 0 - 替换已知值:(0 || 0) == (false or false) == false == 0
  • (x || !y && z) == 1:这里是关键!从上面我们知道:
    • x || !y 是 1/true,如果相关,则意味着 1/true && z/0/false == 1/true <- 这显然没有任何意义,因此它不是 C/C++ 计算答案的方式!
    • (!y && z) 是 false,如果相关,则意味着 x/2/true || false == 1/true <- 这是正确的,所以它必须是隐含的顺序。
通过这种方式,我们已经推导出了运算符优先级 - || 和 && 运算符的求值顺序,从编译器显示的结果中看到,只有当 && 在 || 之前求值时,我们才能理解结果。

-1
answer = 1

或者也许:

answer = -27
2 || !1 && 0
2 || 0 && 0
2 || 0
true
true = non-zero value
printf("answer = %d",*true*); -> who knows

大多数编译器将输出answer = 1。虽然我不敢确信所有编译器都会这样做,但我确信所有编译器都会返回非零值。


4
错了,短路是无关紧要的,这只涉及是否发生副作用。这是一个简单的运算符优先级问题。如果你不相信我,请尝试将“&&”替换为“,”(逗号运算符)。 :-) 注:该段话暗示短路和运算符优先级之间的关系,并建议使用逗号运算符来演示这一点。 - R.. GitHub STOP HELPING ICE
2
不,答案总是1。逻辑AND和OR的结果始终是一个值为0或1的“int”。C++也是一样的,只是类型是“bool”,当传递给“printf”时会提升为“int”。 - Derek Ledbetter
1
现在你错了,但是原因不同了。答案总是1。在C语言中,逻辑运算符的结果定义为0或1;这不是一个实现问题。 - R.. GitHub STOP HELPING ICE
@R.: 这个问题被标记为C和C++。 - Jens Gustedt
@R C有着悠久的历史,比C标准要长得多。第一个C编译器在70年代中期问世,而第一个C标准则是在89年左右出现的。当使用一种实现远先于标准的语言时,它总是一个实现问题。在C语言中,真 <-> 非零关系很普遍。随意测试每个已编写的C编译器,并证明它们都没有按照这种方式工作-除此之外-无法销售。然而,我将更新我的帖子,将“C兼容”更改为指示可能从编译器返回的内容。 - PatrickV
为什么没人踩这个?如何将true变成非1的值?为什么运算符优先级在这里不相关? - phuclv

-2

我不会直接给你答案,因为你可以编译并运行它,但这个问题只是在测试你是否了解运算符优先级。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接