我对一些同事在以下代码中存在分歧:
int foo ( int a, int b )
{
return b > 0 ? a / b : a;
}
此代码是否显示未定义的行为?
编辑:分歧开始于过度热切的优化编译器中的错误,其中b > 0
检查已经过优化。
答案 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_MIN
和b == -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的排序显然是为了特别允许这种类型的构造。我无法想象你的同事会与之争辩