提问人:Yurii Kapusta 提问时间:9/24/2023 最后编辑:Jan SchultkeYurii Kapusta 更新时间:9/25/2023 访问量:133
在这个复杂的表达式中,运算符的优先级/求值顺序是什么,为什么结果是 -129?
What is the operator precedence/order of evaluation in this complex expression, and why is the result -129?
问:
我不明白操作在 C++ 表达式中发生的顺序。
例如: 为什么我们到了-129?你能解释一下行动的顺序吗?
#include <stdio.h>
int main()
{
char a = 60;
unsigned c = 88;
long d = 134;
int e = -6;
printf("Reuslt: %ld\n",!a++<sizeof(long double)&(c)|~d--+-e );
return 0;
}
我尝试使用 int k1、k2、k3、...、kn(其中 k 代表 1 个动作)的动作来做到这一点,但我还不明白动作的顺序。
答:
我不会给你确切的答案,因为这是一个练习,最终是你需要解决它。但我会给你你需要的信息,以便解决这个问题。
优先 级:
!
: 3a++
: 2<
: 9sizeof()
: 3a&b
: 11|
: 13~
: 3d--
: 2+
: 6-e
: 3
来源: https://en.cppreference.com/w/cpp/language/operator_precedence
当我们谈论相同优先级的操作时,人们会期望顺序是从左到右的(除了特殊情况,例如分配,这里不存在,我们从哪里到右),顺序作的优先级覆盖。优先级编号越低,操作的优先级越高。
例如,将执行第一个,然后执行 ,因为优先级较高(较低的 prio 数表示前面的运算符)。因此,建议你拿笔和纸画出表达式树。!a++
++
!
++
这将使您了解这里究竟发生了什么以及以什么顺序发生。尝试在不查看表达式的实际结果的情况下弄清楚这一点,并将您获得的结果与稍后使用表达式测试的结果进行比较,而不会受到影响。如果结果匹配,那么很可能(但不是 100% 证明)您是正确的。如果结果不匹配,则说明有问题。
如果结果不匹配,则隔离表达式树的子树并分别评估它们,直到您获得导致不匹配的确切原因,然后您就会明白为什么您错了。
你有。。。
!a++ < sizeof(long double) & (c) | ~d-- + -e
...因此,让我们从 C++ 运算符优先级表中获取我们需要的内容,并添加括号以阐明如何解释表达式:
优先 | 算子 | 描述 | 关联性 |
---|---|---|---|
2 | a++ a-- |
后缀/后缀递增和递减 | 从左到右 |
3 | +a -a |
一元正负 | 从右到左 |
! ~ |
逻辑 NOT 和按位 NOT | ||
sizeof |
尺寸 | ||
6 | a+b a-b |
加法和减法 | 从左到右 |
9 | < <= > >= |
对于关系运算符,分别为 < 和 ≤ 以及 > 和 ≥ | -"- |
11 | a&b |
按位 AND | -"- |
13 | | |
按位 OR(包括 OR) | -"- |
- 2. 对于和:
a++
d--
!(a++) < sizeof(long double) & (c) | ~(d--) + -e
- 3. 对于 、 和 (我在这里省略了括号):
!(a++)
sizeof
~(d--)
-e
sizeof(type)
(!(a++)) < sizeof(long double) & (c) | (~(d--)) + (-e)
- 6. 对于:
(~(d--)) + (-e)
(!(a++)) < sizeof(long double) & (c) | ((~(d--)) + (-e))
- 9. 对于:
(!(a++)) < sizeof(long double)
((!(a++)) < sizeof(long double)) & (c) | ((~(d--)) + (-e))
- 11. 对于:
((!(a++)) < sizeof(long double)) & (c)
(((!(a++)) < sizeof(long double)) & (c)) | ((~(d--)) + (-e))
- 13. 此时只剩下这些了,所以这些围绕着整个表达式:
|
((((!(a++)) < sizeof(long double)) & (c)) | ((~(d--)) + (-e)))
还有带括号的表达式,可以更清楚地说明哪些子表达式联系在一起,您现在只需要从内括号中解开混乱并取出即可。
- 有关更深入的了解,请参阅此 C++ 运算符优先级 Wiki
由于 和 稍后不会在代码中使用,因此您可以忽略并删除 post 递增和递减运算符
a
d
((((!(a)) < sizeof(long double)) & (c)) | ((~(d)) + (-e)))
!a
是0
((((0) < sizeof(long double)) & (c)) | ((~(d)) + (-e)))
0 < sizeof(long double)
给出 true 或1
(((1) & (c)) | ((~(d)) + (-e)))
c
是偶数,因此结果为1 & c
0
((0) | ((~(d)) + (-e)))
按位保留任何内容,因此可能会被删除
0 | anything
(~(d)) + (-e)
+(-e)
是基本的算术(~(d)) - e
这些只是简单的操作,将表达式减少到最低限度。剩下的表达式是 just or ,由差值(或总和)和按位 not 组成。为此,您需要了解二进制算术和 Two 补码(维基百科)。
(~d) - e
(~134) + 6
感谢 @user17732522 的评论:按位 or: 有一个转折点,另请参阅隐式转换 (cppreference)。
0 | anything
- 由于操作数具有类型 和 ,第一个操作数 () 将被转换为,结果如问题中所述。
unsigned int
signed long
0
signed long
- 如果操作数是 ,则第二个操作数 () 将被转换为 并且结果不同。
unsigned int
signed int
(~d) - e
unsigned int
- 由于操作数具有类型 和 ,第一个操作数 () 将被转换为,结果如问题中所述。
评论
d
int
long
评论