微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

&& 是否在评估右侧的更高排名运算符之前强制评估其左侧的关系算术运算符C99?

如何解决&& 是否在评估右侧的更高排名运算符之前强制评估其左侧的关系算术运算符C99?

考虑以下代码

int y,x; y = 2; x = 0;

x!=0&&y/x>5

我的讲师关于 C 的教科书提供了一个表格,用于“算术、关系和逻辑运算符的优先级层次结构” 使用此表评估上述表达式中的运算符,我得到以下优先级:

(1) 是 /,因此,先做 y/x

(2) 是 >,(3) 是 !=,(4) 是 &&。

如果我使用这个优先级来评估上面的代码,那么第一个要评估的子表达式是: y / x 这是 2 / 0,或未定义...

给出的答案是 0。

后来,教科书还指出,根据 ANSI C 标准,&& 左侧的操作数将始终首先计算,并且只有当它为 0 时,才会计算右侧的操作数。

这是否意味着每当 逻辑和 (&&) (或逻辑或(||))出现在一个表达式以及算术和关系运算符,实际上我需要将整个表达式的术语分为两组 - && 左侧的术语和右侧的术语,然后才开始应用 ”算术、关系和逻辑运算符的优先层次结构" 到包含在整个“左手操作数”中的运算符?

这将导致上述表达式被评估为:

(x!=0) && (y/x>5)

从左操作数 (x!=0) 开始,即 (0!=0) 为假,因此为 0,因此不会进行进一步的评估。

--

如果是这种情况,如果 && 运算符包含在表达式中指示必须首先执行什么操作,那么为什么它在优先级层次结构中出现如此低的位置?

解决方法

在这种情况下,您会遇到称为“短路评估”的问题。将您的条件 if (x != 0 && y / x > 5) 视为 if (somethingIsTrue && somethingIsTrue)。为了使它成为真的,它必须变成if (true && true)。在短路评估中,它看到 x !=0 为假并立即停止评估,因为无论后面发生什么,第一件事都是假的,所以它永远不会是真的。

是的,就您而言,您可以将其视为将表达式拆分为 && 和 || 之间的组声明。这些单独的表达式中的每一个都被评估为真或假,然后只需将其视为 && 和 || 之间的一堆真或假语句声明。因此,对于像 if (blah1 && blah2 || blah3) 这样的东西,无论 blah1、blah2 和 blah3 是什么,它们都会被评估为 true 或 false。然后你就可以看到它是如何播放的,比如 if (true && true || false) 或类似的东西。

顺便说一句,不要用头撞墙试图记住优先规则。它们中的大多数都很直观,随着您编程的增多,您将掌握正确的做事方法。

,

运算符的优先级明确了表达式 x!=0&&y/x>5 的解释方式。将其视为设置大括号。因此,编译器会将您的表达式读取为 (x!=0) && ((y/x)>5)。请注意,优先级最高的运算符先得到大括号,优先级较低的运算符在后得到大括号。

现在进行评估。评价是从外到内进行的。最外面的运算符是优先级最低的运算符,&&。它有两个操作数,左一个和右一个。现在标准说要先评估左边的。如果是 false,则 && 返回 false(快捷方式)。如果是 true,则需要计算正确的操作数。

这个有保证的评估顺序的好处是您现在可以安全地编写例如 if (x!=0 && y/x>10)if (pointer!=NULL && pointer->data != 3)

,

优先级和结合性仅说明如何构造表达式。他们没有说如何评价它。考虑x+y*z。如果不是为了优先,我们可以将此表达式构造为 (x+y)*z,显示在左侧,或 x+(y*z),显示在右侧。

    *                +
   / \              / \
  +   z            x   *
 / \                  / \
x   y                y   z

优先级告诉我们使用后者。但是我们仍然可以按任意顺序计算 xyz。假设xyz实际上是有副作用的函数调用;也许他们会打印“x”、“y”和“z”。如果我们评估z并记住它的结果,然后评估y,然后将它们相乘,然后评估x,然后添加,我们将得到与评估{{1}相同的结果}},然后是x,然后是y,然后相乘,然后相加。

这两个求值顺序使用相同的表达式结构,后者。所以给我们表达式结构的优先级并没有告诉我们如何计算表达式。 (几乎——该结构确实迫使我们在将其用于加法之前获得乘法的结果。)

z&& 运算符有一个超越优先级的属性:它们的规则是先计算左操作数,只有在左操作数不能确定结果时才计算右操作数.

深入挖掘,有两个与某些表达式相关的计算。每个表达式都有其主要作用:产生一个值,例如其操作数的和、积或逻辑与。某些表达式也有副作用,例如增加对象(在 || 中)或写入输出(x++)。副作用不必与主要效果同时进行。一般来说,它可以在它所在的完整表达式中的任何时间进行,可以在主效应之前、期间或之后。

putchar('c')&& 运算符的排序属性扩展到副作用:它们要求在评估右操作数的任何部分之前完成其左操作数的所有副作用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。