Luchian Grigore
Luchian Grigore

Reputation: 258548

Is unevaluated division by 0 undefined behavior?

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.

Upvotes: 62

Views: 4102

Answers (5)

Keith Thompson
Keith Thompson

Reputation: 263167

No, because it doesn't satisfy the C standard's definition of "undefined behavior".

I'll quote the N1570 draft of the C11 standard. Other editions have nearly or exactly the same wording.

3.4.3 defines the term undefined behavior as:

behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

3.4 defines behavior as:

external appearance or action

Examples of behavior are input and output:

if (1) {
    printf("This is behavior\n");
}
else {
    printf("This is not behavior.\n";
}

A division by zero (or anything else) that is never evaluated has no "external appearance or action", therefore is it not behavior, therefore it cannot be undefined behavior.

Upvotes: 1

pm100
pm100

Reputation: 50100

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

Upvotes: 3

krzaq
krzaq

Reputation: 16421

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.

Upvotes: 112

haccks
haccks

Reputation: 105992

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.

Upvotes: 10

glauxosdever
glauxosdever

Reputation: 652

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.

Upvotes: 15

Related Questions