Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dividing by zero in a constant expression

My toy compiler crashes if I divide by zero in a constant expression:

int x = 1 / 0; 

Is this behaviour allowed by the C and/or C++ standards?

like image 679
fredoverflow Avatar asked Nov 25 '15 12:11

fredoverflow


People also ask

What is a constant divided by 0?

A number divided by 0 is undefined. . The result is 1.

What happens if you divide something by 0?

Instead, any number divided by zero is undefined. In fact, even zero divided by zero is undefined! That simply means we don't yet have an answer for the problem.

Is dividing by zero infinity or undefined?

The thing is something divided by 0 is always undefined because the value has not been defined yet.

Can we divide 0 by a number?

Because what happens is that if we can say that zero, 5, or basically any number, then that means that that "c" is not unique. So, in this scenario the first part doesn't work. So, that means that this is going to be undefined. So zero divided by zero is undefined.


1 Answers

Yes, division by zero is undefined behavior and neither the C nor C++ standard impose any requirements in such cases. Although in this case I believe you should at least issue a diagnostic(see below).

Before I go quoting the standards, I should note that although this may be conformant behavior quality of implementation is a different issue, being merely conforming is not the same as being useful. As far as I know the gcc, clang, Visual Studio and Intel(as per tpg2114) team consider internal compiler errors(ICEs) to be bugs that should be reported. It should be noted that both current gcc and clang produce a warning for this case seemingly regardless of flags provided. In the case where both operands are literals/constants, the case we have here, it seems rather straight forward to detect and provide a diagnostic for this. clang produces the following diagnostic for this case (see it live):

warning: division by zero is undefined [-Wdivision-by-zero] int x = 1 / 0 ;           ^ ~ 

From the draft C11 standard section 6.5.5 Multiplicative operators (emphasis mine):

The result of the / operator is the quotient from the division of the first operand by the second; [...] if the value of the second operand is zero, the behavior is undefined.

and so it is undefined behavior.

The draft C++ standard section 5.6 [expr.mul] says:

The binary / operator yields the quotient [...] If the second operand of / or % is zero the behavior is undefined [...]

again undefined behavior.

Both the draft C++ standard and draft C standard have a similar definition for undefined behavior both saying:

[...]for which this International Standard imposes no requirements

The phrase imposes no requirements seems too allow any behavior, including nasal demons. Both have a similar note saying something along the lines of:

Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

So although notes are not normative, it seems like if you are going to terminate during translation, you should at least issue a diagnostic. The term terminating is not defined, so it is hard to argue what this allows. I don't think I have seen a case where clang and gcc have an ICE without a diagnostic.

Does the code have to be executed?

If we read Can code that will never be executed invoke undefined behavior? we can see at least in case of C there is room for debate where the 1 / 0 has to be executed in order to invoke undefined behavior. What is worse in the C++ case the definition of behavior is not present so part of the analysis used for the C case can not be used for the C++ case.

It seems that if the compiler can prove the code will never be executed then we can reason that it would be as-if the program did not have undefined behavior but I don't think this is provable, just reasonable behavior.

From the C perspective WG14 defect report 109 further clarifies this. The following code example is given:

int foo() {   int i;   i = (p1 > p2); /* Must this be "successfully translated"? */   1/0; /* Must this be "successfully translated"? */   return 0; }  

and the response included:

Furthermore, if every possible execution of a given program would result in undefined behavior, the given program is not strictly conforming.
A conforming implementation must not fail to translate a strictly conforming program simply because some possible execution of that program would result in undefined behavior. Because foo might never be called, the example given must be successfully translated by a conforming implementation.

So in the case of C, unless it can be guaranteed that the code invoking undefined behavior will be executed then the compiler must successfully translate the program.

C++ constexpr case

If x was a constexpr variable:

constexpr int x = 1 / 0 ; 

it would be ill-formed and gcc produces a warning and clang makes it error (see it live):

error: constexpr variable 'x' must be initialized by a constant expression constexpr int x = 1/ 0 ;              ^   ~~~~ note: division by zero constexpr int x = 1/ 0 ;                   ^ warning: division by zero is undefined [-Wdivision-by-zero] constexpr int x = 1/ 0 ;                   ^ ~ 

Helpfully noting that division by zero is undefined.

The draft C++ standard section 5.19 Constant expressions [expr.const] says:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions

and includes the following bullet:

an operation that would have undefined behavior [Note: including, for example, signed integer overflow (Clause 5), certain pointer arithmetic (5.7), division by zero (5.6), or certain shift operations (5.8) —end note ];

Is 1 / 0 a constant expression in C11

1 / 0 is not a constant expression in C11, we can see this from section 6.6 Constant expressions which says:

Each constant expression shall evaluate to a constant that is in the range of representable values for its type.

although, it does allow:

An implementation may accept other forms of constant expressions.

So 1 / 0 is not a constant expression in either C or C++ but that does not change the answer since it is not being used in a context that requires a constant expression. I suspect the OP meant that 1 / 0 is available for constant folding since both operands are literals, this would also explain the crash.

like image 176
Shafik Yaghmour Avatar answered Oct 05 '22 15:10

Shafik Yaghmour