提问人:Luchian Grigore 提问时间:10/21/2016 最后编辑:Luchian Grigore 更新时间:11/21/2016 访问量:4024
未计算除以 0 是未定义的行为吗?
Is unevaluated division by 0 undefined behavior?
问:
我与一些同事在以下代码上存在分歧:
int foo ( int a, int b )
{
return b > 0 ? a / b : a;
}
此代码是否表现出未定义的行为?
编辑:分歧始于一个过于急切的优化编译器中的一个错误,其中检查被优化了。b > 0
答:
哈哈
来自 N4140 的报价:
§5.16 [expr.cond]/1
条件表达式按从右到左的顺序分组。第一个表达式是 在上下文中转换为布尔值。它被评估,如果它为 true,则 条件表达式的结果是第二个的值 表达式,否则为第三个表达式。仅计算第二个和第三个表达式中的一个。
进一步:
§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 }
在上面的示例中,用于初始化(或除 之外的任何内容)是未定义的。然而,明确指出,只有在评估 UB 分支时才会发生 UB。d
int
unsigned char
从语言律师的角度来看:如果这可能是 UB,那么任何除法都可以被视为 UB,因为除数可能是 0。这不是规则的精神。
评论
§5 [expr]/4
cout << "a/b: " << a/b << endl; return b != 0 ? a / b : a;
在示例代码中,无法用零除法。当处理器执行时,它已经检查了 ,因此不为零。a / b
b > 0
b
应该注意的是,if 和 ,then 也是未定义的行为。但无论如何,这都是可以防止的,因为在这种情况下,条件的评估结果为。a == INT_MIN
b == -1
a/b
false
虽然我不太确定你的意思不是如果 b 小于零,除非是上述条件,否则除法仍然有效。return b != 0 ? a / b : a;
return b > 0 ? a / b : a;
评论
a / b
b
此代码是否表现出未定义的行为?
哈哈事实并非如此。表达式
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
评论
a/b
如果这是UB,那么也会
if(a != null && *a == 42)
{
.....
}
ifs、ands和ors的排序显然是为了专门允许这种类型的构造而设计的。我无法想象你的同事会对此提出异议
评论
return p ? p->flag_value : false
p