Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这是Visual Studio编译器错误';除以或模零';虫子?_C++_Visual Studio - Fatal编程技术网

C++ 这是Visual Studio编译器错误';除以或模零';虫子?

C++ 这是Visual Studio编译器错误';除以或模零';虫子?,c++,visual-studio,C++,Visual Studio,我在Visual Studio 2019上,当我尝试编译此文件时: #包括 int main(){ (-2147483647 - 1) / -1; INT_MIN/-1; } 在这两种情况下,我都会遇到编译器错误: C2124 'divide or mod by zero' 在我看来,没有除法或模乘零。通过将警告级别调高,编译器可以揭示根本原因: main.cpp(4,23): warning C4427: '/': overflow in constant division, undefi

我在Visual Studio 2019上,当我尝试编译此文件时:

#包括
int main(){
(-2147483647 - 1) / -1;
INT_MIN/-1;
}
在这两种情况下,我都会遇到编译器错误:

C2124 'divide or mod by zero'

在我看来,没有除法或模乘零。

通过将警告级别调高,编译器可以揭示根本原因:

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
你有一个UB,MSVC决定通过溢出到零来处理它。因为新值为零,所以执行除法,编译器会抱怨被零除法


编码时,将警告设置为高级别4,并启用“将警告视为错误”。这样,您将被迫修复警告。第一个警告很可能是随后所有其他问题的原因。通过强制修复列表中的第一个警告,您可能会修复大部分或所有其他问题。

C11的n1570草案在第6.5.5节乘法运算符§6(强调我的):

当整数被除时,/运算符的结果是具有任意值的代数商 部分被丢弃如果商a/b是可表示的,则表达式 (a/b)*b+a%b应等于a否则,a/b和a%b的行为都是 未定义

我们在角落里。让我们做一次运算,暂时忘记表示:

-2147483647 - 1 = -2147483648       (1)
-2147483648 / (-1) = 2147483648     (2)
现在我们有一个系统,在2-补码中有32位整数。所以INT_MAX是2147483647,INT_MIN是-2147483648

所以(1)很好,我们得到的INT_MIN可以表示为有符号的INT,但是(2)给出的INT_MAX+1不能表示。因此,该操作似乎有效,但其结果不能用int表示。由于§6,结果明确未定义,任何行为从标准角度来看都是合法的。因此,当MSVC决定在实际问题不是0的情况下提出除法误差时,这是符合标准的

我经常讨厌微软的错误消息,因为它们与此无关,但除了这里,整数溢出不会引发任何错误,结果会通过在32位上删除位而悄悄地带入[INT_MIN,INT_MAX]。但是这里你会得到x/(-1)==x,而这是除法中唯一可能的溢出。MSVC设计人员认为,这确实是一个需要引发错误的特殊情况。他们搜索除法可能引起的错误,只找到0的除法,所以他们使用了它


他们本可以使用更明确的信息,但由于标准允许任何行为,他们只是选择了最便宜的方式…

问题是
-INT\u MIN
超出了
INT\u MAX
的范围。这是二的补码运算的结果。编译器和运行时在除法过程中报告溢出是一种常见的零除错误,这至少在一定程度上是因为在硬件层面上,这两种情况都有相同的例外。溢出的部分,以及你所说的MSVC可能是通过溢出到零来处理的,是除数符号(/)(被除数)之前的部分,它仍然被除以-1,对吗,不是零。所以没有0的除法?这只是编译器消息中的一个错误?@Zebrafish您正在调用UB。任何事情都有可能发生。谷歌
c++调用UB
提供了一个关于编译器如何假设没有UB的答案,特别是你正在做的事情:签名溢出就是UB。这个解释是不正确的。给定带有2s补码编码的32位整数,
-2147483647-1
不会溢出,正如这个答案所示。当该值除以
-1
时会发生溢出,因为它不再表示为32位2s补码整数。目前还不清楚这些是如何触发C2114的。UB与此无关;指的是虚拟抽象机。编译器是非常真实的,通常表现出可预测的行为。@IInspectable目前的解释可能不正确,但这是错误的。因此,从字面上说,任何解释都是正确的P实现者可以做任何它想做的事情。下一个版本的VS可能会做一些完全不同的事情,即使你的解释也不正确。无论如何,调用UB:“不要那样做”。
(INT\u MIN+1)-1
对于任何实现都是定义良好的。如果你说这是要展示UB,那你就错了。结论是,只要有UB,犯错是完全可以的,这是很难证明的。我不会说“最便宜”的方式。这更像是“因为标准上说“你可以做任何事情”,所以他们抛出了一个已经存在的错误,称之为好的。它比“任何东西”都被解释为“格式化硬盘”要好。