未定义的行为是否未被评估?
我对以下代码与一些同事存在分歧:
int foo ( int a, int b ) { return b > 0 ? a / b : a; }
这段代码是否performance出未定义的行为?
编辑:分歧从什么似乎是过度急切的优化编译器,其中b > 0
检查被优化出来的错误。
没有。
来自N4140的引述:
§5.16[expr.cond] / 1
条件expression式从右到左分组。 第一个expression式被上下文转换为bool。 它被评估,如果它是真的,条件expression式的结果是第二个expression式的值,否则第三个expression式的值。 只有 第二个和第三个expression式中的一个被评估 。
进一步:
§5[expr] / 4
如果在expression式评估过程中,结果不是math定义的,或者不在其types的可表示值范围内,则行为是未定义的。
这显然不会发生在这里。 同一段在一个注释中明确提到零除,虽然它是非规范性的,但它更加清楚地表明它与这种情况有关:
[注:大多数现有的C ++实现忽略整数溢出。 除零的处理,使用零除数形成余数,并且所有浮点exception在机器之间变化,并且通常可以通过库函数进行调整。 – 注意]
还有一些间接证据强化了上述观点:条件操作符被用来有条件地使行为不被定义。
§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分支被评估的情况下才会发生。
从语言律师的angular度出发:如果这可能是UB,那么任何部门都可以被视为UB,因为除数可能为0.这不是规则的精神。
示例代码中无法用零来划分。 当处理器执行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;
而不是return b > 0 ? a / b : a;
return b > 0 ? a / b : a;
如果b小于零,除非是上述条件,否则除法仍然有效。
这段代码是否performance出未定义的行为?
不,不。 expression方式
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
大于0
时才会执行除法。
如果这是UB,那么也是如此
if(a != null && *a == 42) { ..... }
ifs,ands和ors的sorting明确地被devise为专门允许这种types的构造。 我无法想象你的同事会这样争论