简体   繁体   中英

Is this Visual Studio compiler error 'divide or mod by zero' a bug?

I'm on Visual Studio 2019, and when I try to compile this:

#include <iostream>

int main() {
    (-2147483647 - 1) / -1;
    INT_MIN / -1;
}

I get a compiler error in both cases:

C2124 'divide or mod by zero'

There's no divide or mod by zero as far as I can see.

By turning the warning level up the compiler reveals the root cause:

main.cpp(4,23): warning C4427: '/': overflow in constant division, undefined behavior
main.cpp(5,13): warning C4427: '/': overflow in constant division, undefined behavior
main.cpp(4,1): error C2124: divide or mod by zero

You have UB which MSVC has decided to handle by overflowing to zero. Because the new values are zero, then the division is performed, the compiler complains about division by zero.

When coding, have your warnings set as high as Level 4 with Treat Warnings As Errors turned on. This way you are forced to fix your warnings. Most likely the first warning is the cause of all the other problems afterwards. By being forced to fix the first warning in the list you potentially fix most or all of the other problems.

Draft n1570 for C11 says at 6.5.5 Multiplicative operators §6 (emphasize mine):

When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. If the quotient a/b is representable , the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined .

And we are in the corner case. Let us do the operation forgetting for a while the representation:

-2147483647 - 1 = -2147483648       (1)
-2147483648 / (-1) = 2147483648     (2)

Now we have a system with 32 bits integers in 2-complement. So INT_MAX is 2147483647 and INT_MIN is -2147483648

So (1) is fine and we get INT_MIN that can be represented as a signed int. But (2) gives INT_MAX + 1 which cannot. So the operation seems valid, except that its result cannot be represented by an int. Because of §6, the result is explicitely undefined and any behaviour is legal on a standard point of view. So when MSVC decides to raise a division by 0 error when the actual problem is not that, it is standard conformant.

I often hate Microsoft error messages for not being relevant, but except here integer overflow never raise any error, and the result is silently brought into the [INT_MIN,INT_MAX] by dropping bits over 32. But here you would get x / (-1) == x, while it is the only possible overflow in division. MSVC designers decided that it was really a special case that required to raise an error. They searched for the possible errors raised by a division and only found the division by 0, so they used it.

They could have used a more explicit message, but as the standard allowed any behaviour they just choosed the cheapest way...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM