C 运算符优先级不明确,请解释为什么这里不遵循运算符优先级?
运算符优先级如下所示-- 所以答案应该是--C 运算符优先级不明确,请解释为什么这里不遵循运算符优先级?,c,C,运算符优先级如下所示-- 所以答案应该是-- 但是,答案是2,1,1。表达式中没有序列点: 1. 2||2 && 2 2. 2||1 3. 1 print x,y,z should be 2,2,1 在z的预增量和z的赋值之间 因此,如果实际计算了++z,这会立即将您置于未定义的行为区域,任何事情都可能发生。不允许在没有中间序列点的情况下修改同一对象两次。附录C(来自C99)列出了所有序列点,此处的控制点遵循完整表达式(整个计算和赋值) 6.5表达式/2说明: 在上一个
但是,答案是2,1,1。表达式中没有序列点:
1. 2||2 && 2
2. 2||1
3. 1
print x,y,z should be 2,2,1
在z
的预增量和z
的赋值之间
因此,如果实际计算了++z
,这会立即将您置于未定义的行为区域,任何事情都可能发生。不允许在没有中间序列点的情况下修改同一对象两次。附录C(来自C99)列出了所有序列点,此处的控制点遵循完整表达式(整个计算和赋值)
6.5表达式/2
说明:
在上一个序列点和下一个序列点之间,对象的存储值最多应通过表达式的计算修改一次。此外,之前的值应为只读,以确定要存储的值
但是,如果初始值x
为1,则在这种特殊情况下,表达式的++z
部分不会计算。这并没有降低表达式本身的危险性,因为在起点为x=-1
和y!=-1
在这种情况下,标准的控制部分是6.5.14逻辑或运算符/4
:
与按位|运算符不同,| |运算符保证从左到右求值第一个操作数求值后有一个序列点如果第一个操作数与0比较不相等,则不计算第二个操作数。
因此,首先计算
++x
,因为它的计算结果不是零,++y&&++z
x
增加到2
,z
设置为该值的“真实”值,或1
,y
在1
表达式处保持不变,带有逻辑运算符&
和|
从左到右求值:
C99,第6.5.14-4节与按位|
运算符不同,|
运算符保证从左到右求值;第一个操作数求值后有一个序列点。如果第一个操作数与0
比较不相等,则不计算第二个操作数
由于
x++
不是零,表达式会对|
右侧的所有内容(包括其副作用)进行短路计算。这就是为什么只计算x++
,所以x
变成2
。其余变量应保持在1
。优先级与求值顺序不同。优先级只是决定哪些操作数和运算符属于同一类。除逻辑运算符的外,计算的准确顺序未指定,逻辑运算符严格按照从左到右的顺序进行计算,以启用短路
因此,由于&&
具有更高的优先级,因此首先将变量分组如下:
z = ++x || ++y && ++z;
然后,按照从左到右的顺序计算
++x
。假定++x
为真,则已知整个表达式为真。所以表达式求值是短路的<代码>(++y&&&++z)永远不会被计算。因此y和z永远不会增加 @aaronman我也提到了优先顺序。!由于&&具有更高的优先级,将首先对其求值,不是吗?所以++y和++z应该执行。@paxdiablo关于优先级,你可能是对的,但我同意不是UB@aaronman,我建议你看看标准的附录C,很清楚序列点是什么。@aaron,那是因为它不是一个精确的副本。在该问题中,没有分配给c/z
,因此它不是UB。这个问题和作业是一样的。@paxdiablo你是对的,从左到右的陈述太笼统了。我编辑以澄清。谢谢@dasblinkenlight,他修改了两次z
,没有插入序列点,前增量和赋值。如果没有作业,这将是一个顺序评估问题。有了这个,就是UB。啊,是的-我看了看=
的右侧,没有看到他在修改z
两次!!!关于UB,您的任务分配到z
,这是绝对正确的。但是,即使没有赋值z
,结果仍然是一样的()。当x在开始时是1
时,子表达式++z
没有计算,因此没有UB。@Cubbi,我相信你误解了UB。编译器不一定知道表达式开头的x
的值。因此,它可以自由地生成它想要的任何代码来响应格式错误的源代码,甚至可以什么都不做,或者将所有变量设置为42。UB的定义不仅仅是因为输入表达式的数据发生了变化。某些错误行为的概率可能很低,但可能性不受任何限制(根据C99 3.4.3/2)。您可能希望澄清,除了短路操作人员| |
和&
,在这种情况下,评估的准确顺序是严格从左到右的。谢谢@dasblinkenlight。我做了相应的编辑。
1. 2||2 && 2
2. 2||1
3. 1
print x,y,z should be 2,2,1
z = ++x || ++y && ++z;
(++x) || (++y && ++z)