Jay*_*esh 97 c++ floating-point gcc divide-by-zero
情况1:
#include <iostream>
int main()
{
double d = 15.50;
std::cout<<(d/0.0)<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它编译时没有任何警告和打印inf.好的,C++可以处理除零,(实时查看).
但,
案例2:
#include <iostream>
int main()
{
double d = 15.50;
std::cout<<(d/0)<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
编译器发出以下警告(请参见实时):
warning: division by zero [-Wdiv-by-zero]
std::cout<<(d/0)<<std::endl;
Run Code Online (Sandbox Code Playgroud)
为什么编译器会在第二种情况下发出警告?
是0 != 0.0吗?
编辑:
#include <iostream>
int main()
{
if(0 == 0.0)
std::cout<<"Same"<<std::endl;
else
std::cout<<"Not same"<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Same
Run Code Online (Sandbox Code Playgroud)
Mot*_*tti 107
浮点除以零由IEEE很好地定义并给出无穷大(根据分子的值(或NaN对于±0)为正或负).
对于整数,没有办法表示无穷大,语言定义了具有未定义行为的操作,因此编译器有助于引导您从该路径中清除.
但是在这种情况下,由于分子是a double,divisor(0)也应该被提升为double,并且没有理由在这里发出警告而没有给出警告,0.0所以我认为这是一个编译器错误.
M.M*_*M.M 41
在标准C++中,两种情况都是未定义的行为.可能发生任何事情,包括格式化硬盘.你不应该期望或依赖"返回inf.好"或任何其他行为.
编译器显然决定在一个案例而不是另一个案例中发出警告,但这并不意味着一个代码是好的而一个代码没有.这只是编译器生成警告的一个怪癖.
从C++ 17标准[expr.mul]/4:
二元
/运算符产生商,二元%运算符从第一个表达式除以第二个表达式得到余数.如果第二个操作数为/或%为零,则行为未定义.
Yks*_*nen 12
我最好的猜测来回答此问题的讨论将是编译器发出警告之前的进行转换int到double.
所以,步骤将是这样的:
/(T, T2),其中T=double,T2=int.std::is_integral<T2>::value是true和b == 0-这将触发警告.T2为double 这当然是推测,并且基于编译器定义的规范.从标准的角度来看,我们正在处理可能的未定义行为.
请注意,根据GCC文档,这是预期的行为
(顺便说一下,似乎这个标志不能在GCC 8.1中明确使用)
-Wdiv-by-zero
警告编译时整数除零.这是默认值.要禁止显示警告消息,请使用-Wno-div-by-zero.没有警告浮点除零,因为它可以是获得无穷大和NaN的合法方式.
在这个答案中,我不会进入UB /非UB的崩溃.
我只是想指出这一点0,并0.0 有不同的,尽管0 == 0.0评估为true.0是int文字,0.0是double文字.
但是在这种情况下,最终结果是相同的:d/0是浮点除法因为d是double,所以0隐式转换为double.
我认为,foo/0和foo/0.0是不一样的.也就是说,第一个(整数除法或浮点除法)的结果效果高度依赖于类型foo,而第二个(它将始终是浮点除法)则不是这样.
两者中的任何一个是UB是无关紧要的.引用标准:
允许的未定义行为包括完全忽略不可预测的结果,在翻译或程序执行期间以环境特征(有或没有发出诊断消息)的特定行为,终止翻译或执行(发布时)一条诊断信息).
(强调我的)
考虑" 建议用作真值的赋值括号 "警告:告诉编译器你真的想要使用赋值结果的方法是明确,并在赋值周围添加括号.结果语句具有相同的效果,但它告诉编译器您知道自己在做什么.可以这样说foo/0.0:由于您通过使用0.0而不是明确告诉编译器"这是浮点除法" 0,编译器会信任您并且不会发出警告.