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

Luc*_*ore 61 c c++ language-lawyer

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

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}
Run Code Online (Sandbox Code Playgroud)

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

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

krz*_*zaq 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
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,使用d初始化int(或其他任何内容unsigned char)是未定义的.然而,明确指出UB仅在评估UB分支时发生.


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

  • @LuchianGrigore你的问题答案的本质完全在斜体句中(*只评估第二和第三个表达式中的一个*).如果某人不理解条件操作的属性,他们可能会产生更多像你的问题,其中除零被替换为取消引用空指针,超出界限访问,预期但未观察到的重要副作用等 (25认同)

gla*_*ver 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小于零,除非它是上述条件,否则除法仍然有效.

  • Hans Olsen指出了一个案例,其中"a/b"仍然可以在评论中对于否定的"b"未定义. (2认同)

hac*_*cks 9

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

不,它没有.表达方式

return b > 0 ? a / b : a;  
Run Code Online (Sandbox Code Playgroud)

相当于

if(b > 0)
    return a/b;     // this will be executed only when b is greater than 0
else
    return a;  
Run Code Online (Sandbox Code Playgroud)

只有当b大于时才执行除法0.

  • @immibis;*问题(如标题中所述)不会询问是否评估除法*:是,但答案在于对除法表达式的评估.这里没有除零. (2认同)