I was trying to understand the differences between res1 and res2 in the code below:
#include <iostream>
int main()
{
int x = 1;
int y = 0;
double res1 = double(x)/y; // OK: evaluates to Inf
int res2 = x/y; // run-time error: Floating point exception
// 1/0; // g++ warning: division by zero [-Wdivision-by-zero]
std::cout << res1;
return 0;
}
From what I understand, division by zero is undefined behaviour in the C++ standard and the reason for the difference between res1 and res2 is due to my machine implementing IEEE 754 for double, which requires division by zero to return Inf or -Inf.
But now I'm wondering why the standard has to make any pronouncements about division by zero in the first place. This answer says it's to accommodate the various different architectures that implement C++, but I'm not sure - isn't division by zero more of a run-time concern? Especially if the compiler is unlikely to be able to detect it in most cases without evaluating the denominator (I think this is what happens in the example above). Of course, if I try something like 1/0, then g++ gives a warning, but in most cases, we would expect the denominator to be a more complex expression.
As I understand your question you seek to know, why explicitly state that division by zero is undefined, and not just omit it from the standard altogether? Here I think there is an important distinction between omitting something from the standard, and specifying that something is not defined.
With regards to evaluation of expressions, it is essentially §5.4 that we are interested in:
Source: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf
If the standard did not include this statement, it would be the interpretation of the reader to basically figure out the same. So the reader would have to find out that the corner case existed, and that it would lead to undefined behavior.
In the C++ standard undefined behavior is also important for other reasons, special rules apply for things that are undefined behavior, such as defined by §5.19 (Constant expressions) that — among other things — state that:
So knowing when something is undefined can be important for the reader of the C++ standard.
Another reason why division by zero needs to be undefined behavior, is exactly as you mentioned, that it occurs at runtime. If it had defined behavior (which it could) the compiler would have to handle all integer division operations, and wrap them with division by zero handling. Since processors could potentially handle division by zero differently and the C++ authors, did not want to enforce an overhead in handling the situation, they deliberately states that it is undefined.
So in a way you could say that it was a run-time concern, but the compiler produces the code that executes the run-time behavior, and the division by zero has the potential to break the normal scope of execution, and is important in other aspects of the language (see comment above about constant expressions), therefore it needs to be defined. But there are also other things that are undefined, that you could say were "run-time concerns" integer overflows for one. As a developer I love to have an idea about what happens, and if I can assume anything about what happens in a given situation. With integer overflow, I would perhaps expect a specific behavior as logical given that it on my architecture behaved in a specific way. In that regard I want my standard to guide me as to what to expect, and what not to expect.