Is unevaluated division by 0 undefined behavior?
C++CLanguage LawyerC++ Problem Overview
I'm having a disagreement with some co-workers over the following code:
int foo ( int a, int b )
{
return b > 0 ? a / b : a;
}
Does this code exhibit undefined behavior?
EDIT: The disagreement started from what appears to be a bug in an overly-eager optimizing compiler, where the b > 0
check was optimized out.
C++ Solutions
Solution 1 - C++
No.
Quotes from N4140:
> §5.16 [expr.cond]/1 > > Conditional expressions group right-to-left. The first expression is > contextually converted to bool. It is evaluated and if it is true, the > result of the conditional expression is the value of the second > expression, otherwise that of the third expression. Only one of the > second and third expressions is evaluated.
Further:
> §5 [expr]/4 > > If during the evaluation of an expression, the result is not > mathematically defined or not in the range of representable values for > its type, the behavior is undefined.
This clearly does not happen here. The same paragraph mentions division by zero explicitly in a note, and, although it is non-normative, it's making it even more clear that its pertinent to this situation:
> [ Note: most existing implementations of C++ ignore integer overflows. > Treatment of division by zero, forming a remainder using a zero > divisor, and all floating point exceptions vary among machines, and is > usually adjustable by a library function. —end note ]
There's also circumstantial evidence reinforcing the above point: the conditional operator is used to conditionally make behavior undefined.
> §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 > }
In the above example, using d
to initialize int
(or anything other than unsigned char
) is undefined. Yet it is clearly stated that the UB occurs only if the UB branch is evaluated.
Going out of language-lawyer perspective: if this could be UB, then any division could be treated as UB, since the divisor could potentially be 0. This is not the spirit of the rule.
Solution 2 - C++
There is no way of dividing with zero in the example code. When the processor executes a / b
, it has already checked that b > 0
, therefore b
is non-zero.
It should be noted that if a == INT_MIN
and b == -1
, then a/b
is undefined behaviour too. But this is prevented anyway because the condition evaluates to false
in that case.
Although I am not really sure you meant return b != 0 ? a / b : a;
and not return b > 0 ? a / b : a;
If b is less than zero, the division is still valid, unless it is the condition described above.
Solution 3 - C++
>Does this code exhibit undefined behavior?
No. It doesn't. The expression
return b > 0 ? a / b : a;
is equivalent to
if(b > 0)
return a/b; // this will be executed only when b is greater than 0
else
return a;
Division only performed when b
is greater than 0
.
Solution 4 - C++
If this were UB then so would
if(a != null && *a == 42)
{
.....
}
And the sequencing of ifs , ands and ors is clearly designed to specifically allow this type of construct. I cant imagine your colleagues would argue with that