未评估的除以0未定义的行为?

时间:2016-10-21 09:09:28

标签: c++ c language-lawyer

我对一些同事在以下代码中存在分歧:

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}

此代码是否显示未定义的行为?

编辑:分歧开始于过度热切的优化编译器中的错误,其中b > 0检查已经过优化。

4 个答案:

答案 0 :(得分:109)

没有

来自N4140的行情:

  

§5.16[expr.cond] / 1

     

条件表达式从右到左分组。第一个表达是   在上下文中转换为bool。它被评估,如果是真的,那么   条件表达式的结果是第二个的值   表达式,否则表达式的表达式。 只有一个   评估第二和第三个表达式

此外:

  

§5[expr] / 4

     

如果在评估表达式期间,结果不是   在数学上定义或不在可表示值的范围内   它的类型,行为是未定义的。

这显然不会发生在这里。同一段在一个说明中明确提到除零,虽然它是非规范性的,但它更清楚地表明它与这种情况有关:

  

[注意:大多数现有的C ++实现忽略整数溢出。   处理除以零,使用零形成余数   除数,所有浮点异常因机器不同而异   通常可以通过库函数调整。 - 后注]

还有一些间接证据强调了上述观点:条件运算符用于有条件地使行为未定义。

  

§8.5[dcl.init] /12.3

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d; // undefined behavior
  return b ? d : 0; // undefined behavior if b is true
}

在上面的示例中,使用d初始化int(或unsigned char以外的任何内容)未定义。然而,明确指出只有在评估UB分支时才会发生UB。

走出语言 - 律师的角度:如果这可能是UB,那么任何分裂都可以被视为UB,因为除数可能是0。这不是规则的精神。

答案 1 :(得分:15)

在示例代码中无法用零除。当处理器执行a / b时,它已检查b > 0,因此b非零。

应该注意的是,如果a == INT_MINb == -1,那么a/b也是未定义的行为。但无论如何这都会被阻止,因为在这种情况下条件的评估结果为false

虽然我不确定你的意思是return b != 0 ? a / b : a;而不是return b > 0 ? a / b : a;如果b小于零,除非它是上述条件,否则除法仍然有效。

答案 2 :(得分:9)

  

此代码是否显示未定义的行为?

没有。它没有。表达式

library(relsurv)
data(slopop)
is.ratetable(slopop)
# [1] TRUE

is.ratetable(slopop, verbose = TRUE)
# [1] "wrong length for cutpoints 3"

相当于

return b > 0 ? a / b : a;  

仅在if(b > 0) return a/b; // this will be executed only when b is greater than 0 else return a; 大于b时执行分部。

答案 3 :(得分:3)

如果这是UB,那么

if(a != null && *a == 42)
{
 .....
}

ifs,ands和ors的排序显然是为了特别允许这种类型的构造。我无法想象你的同事会与之争辩