【问题标题】:Why does the order of elements in a Boolean expression change the outcome? [duplicate]为什么布尔表达式中元素的顺序会改变结果? [复制]
【发布时间】:2018-03-02 07:39:19
【问题描述】:

如果 x 为 0,则打印 0。如果 y 为 0,我们会得到一个错误。

这是为什么?我唯一能想到的是布尔表达式的编译顺序很重要。如果 x 为 0,则我们得到 (false)&&(error value),其中 false 在左侧,如果 y 为 0,则我们得到 (error value)&&(false)。为什么这会影响打印的内容?

int main(void) {
  int x = 1;
  int y = 0;
  int a = (x/y > 0)&&(y/x > 0);
  printf("%d\n", a);
  return 0;
}

【问题讨论】:

  • 除以零应该触发 SIGFPE。
  • @liliscent:不使用整数除法。
  • 如果 x 为零,则表达式为零并且 &&“短路”。如果 y 为 0,则除以零并调用未定义的行为。没有别的了。
  • @Bathsheba SIGFPE 也会因整数算术错误而引发。
  • @Bathsheba SIGFPE 比浮点运算更具包容性。甚至整数除法溢出也是SIGFPE。

标签: c parsing compilation


【解决方案1】:

与 C 中的大多数其他运算符相比,运算符&& 以“短程序”方式定义了从左到右的评估顺序。即,如果第一个条件失败,则第二个条件甚至不会被评估,因此它不会有失败的机会。请注意,这种“短路”评估不仅仅是一个(可选的)优化问题;它由语言保证。所以下面的表达式永远不会出错:

int x = 1,  y = 0;
int result = (y/x) && (x/y); // OK; y/x yields 0 (meaning false), such that the second operand will not be evaluated.

顺便说一句:运营商|| 也保证了这种短路行为。

【讨论】:

  • 这被标记为 C。虽然在这种情况下语言是相同的。
  • 没错,但我相信y = 0 的错误出现在逻辑运算的第一个操作数中。我应该补充一点,逻辑 OR || 也表现出相同的行为
  • @Stefano Buora:OP 声明“(false)&&(error value)(error value)&&(false)”,这表明它是 x=0;y=1x=1;y=0,但不是 x=0;y=0
【解决方案2】:

x / y 的行为未定义,因为y0

编译器知道y0,并且显然正在优化表达式。它也知道(y/x > 0)就是0,因为&&,整个表达式的结果就是0

较不积极的优化编译器会在运行时引发除以零错误。建议你检查程序集,看看编译器做了什么。

最终成绩:编译器 1,程序员 0。

【讨论】:

  • @Downvoter:我错过了什么?我看不到任何其他解释。
  • 我不是反对者,但我相信您正确地指出了问题所在,您对评论中报告的编译器错误、运行时错误甚至 SIGFPE 的描述应该得到改进。
  • 您的答案也没有回答 OP 的问题,即“为什么布尔表达式中的元素顺序会改变结果?”而不是“为什么除以零会出错?”。这可能是一个有趣的附加信息,但它缺乏对 && 运算符的解释,例如 Stephan Lechners 的回答给出了。这就是我投反对票的原因,a)您假设没有错误,即使 OP 明确指出存在错误,并且 b)根本没有解决 OP 的问题。
  • @MaxVollmer:公平竞争。我认为尽管未来的许多答案都将采用这种形式,因为编译器优化变得更加积极。我不认为它与关于 && 的短路和排序特性的蜡抒情非常相关,因为一旦遇到 UB,所有的赌注都没有了。
  • @MaxVollmer:也许你可以回答。结合斯蒂芬的(恕我直言)答案和我的部分答案。我会赞成。请注意,答案不一定对 OP 有用 - 这不是论坛。如果您想这样做,请告诉我,我会重新打开 - 尽管可以从两个副本中收集答案,但对我来说,副本并不是特别准确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 2018-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多