为什么"++ x || ++ y && ++ z"首先计算"++ x",即使运算符"&&"的优先级高于"||"

liu*_*liu 12 c operator-precedence

为什么先++x || ++y && ++z计算++x,即使运算符的优先级&&高于||

unw*_*ind 43

咦?

如果你说的是&&比那更紧密||(这是真的),那么表达式就等于

++x || (++y && ++z)
Run Code Online (Sandbox Code Playgroud)

由于|| 短路,需要先评估左侧.

如果你的意思是它应该相当于

(++x || ++y) && ++z
Run Code Online (Sandbox Code Playgroud)

同样的情况仍然如此,因为&&短路也意味着||需要首先评估,这反过来++x首先要评估.

  • @halfdan:评价的优先顺序和顺序不是一回事.对于逻辑运算符,评估顺序始终为*从左到右.所有优先级都告诉你,我们正在将`++ x`的结果与`++ y && ++ z`的结果进行或运算,而不是首先评估`++ y && ++ z`. (4认同)
  • @halfdan:不首先评估&&.对于大多数二进制操作,未指定评估操作数的顺序.但是,|| 是短路所以必须首先评估左侧.C99标准明确规定首先评估左侧(6.5.14-4) (2认同)

R..*_*R.. 33

由于&&优先级高于||,它意味着你的表达式相当于:

++x || (++y && ++z)
Run Code Online (Sandbox Code Playgroud)

因此,在程序甚至开始评估结果之前&&,它必须评估++x以确定是否||应该评估右手操作数(逻辑二元运算符是"短路",意味着它们不评估右侧如果左侧足以确定结果).这里没有什么可疑的或编译器特定的.此表达式的行为完全由C标准指定,并且在任何编译器上都是相同的.它甚至可以工作x,因为y,并且z都是相同的变量,因为||&&引入序列点.


Jay*_*Jay 24

放松,R和其他人解释了真正发生的事情.那么我来补充一下:

你的问题的前提是错误的.该事实&&具有更高的优先级并不意味着,围绕着它的操作数必须在表达式中的任何操作数较低的优先级之前评估.即使在特殊情况下,短路||&&这不一定是这样.

例如,考虑a=b+c+d*e; *优先级高于+,但这并不意味着d*e必须先评估b+c.它只是意味着在将产品作为一个整体添加到表达式之前必须对其进行评估.编译器可以评估这个表达式为temp1=d*e,temp2=b+c,a=temp1+temp2或者它可以评估temp1=b+c,temp2=d*e,a=temp1+temp2.两者都同样有效.

随着短路行为||&&有放在评估顺序一些额外的限制.


As a side note: In general I would avoid writing code like this. I can easily see another programmer trying to read this code getting confused about just when the increments will happen and when they won't. Well, maybe if you used real variable names it would not look so bizarre.

I do occasionally rely on short-circuiting preventing side effects. Like

if (!eof() && readNextInt()>0) 
Run Code Online (Sandbox Code Playgroud)

I'm relying on the short-circuit to prevent reading if we're already at end of file, Or

if (confirmDelete==YES && deleteEntry()!=-1) 
Run Code Online (Sandbox Code Playgroud)

I'm relying on the first test to short-circuit on false so I don't do the delete when I shouldn't. But these examples seem pretty straightforward to me, I'd hope any competent programmer would see what I'm doing. But when the examples get cryptic, I think it needs to be broken out. Consider

if (customerType==RETAIL || lastDepositAmount()>100.00)
Run Code Online (Sandbox Code Playgroud)

如果lastDepositAmount()有副作用,那么如果customerType是零售这种副作用永远不会发生.我不认为这对读者来说一定是显而易见的.(部分原因是函数名称暗示它正在检索数据而不执行任何更新,部分原因是客户类型与存款金额之间没有明显的关系 - 这听起来像两个独立的事情.)不可否认,这是主观.但是如果有疑问,请选择简单明了而不是简单的性能提升.总是选择简单和清晰,"嘿,这是一个很酷的使用一个不起眼的功能,任何读这篇文章的人都会对我必须要有多聪明地理解这门语言才能做到这一点印象深刻".


Kon*_*lph 16

这里有可怕的错误答案.

此表达式的评估顺序不依赖于实现.它定义明确!

由于&&绑定高于||,这个表达式相当于++x || (++y && ++z).此外,两个&&||短路,因此,如果表达式的左侧足以确定该值,右手侧是从来没有进行评价.

这是什么情况?好吧,我们知道,无论价值如何,False && a总是会解决False,a特别是即使a不是单个值,而是复杂的表达式.因此我们根本不评估a.同样,True || a总是解决True.

这导致评价在这个例子中一个非常明确的顺序:第一 ++x,然后(如果有的话)++y然后(再次:如果有的话)++z.


Laj*_*pad 6

使用波兰树数据结构评估运算符,如图所示,它是深度优先评估算法.让我们给出操作的名称:A = ++ x B = ++ y C = ++ z D = B && C E = C || D评估顺序:A,B,C,D,E.当然,C有一个优化,如果A为真,那么E将被评估为真而不评估BC和D.同样,如果B为假,则C赢了不进行评估以优化评估速度.

替代文字