簡體   English   中英

C ++警告:將double除以零

[英]C++ warning: division of double by zero

情況1:

#include <iostream>

int main()
{
    double d = 15.50;
    std::cout<<(d/0.0)<<std::endl;
}

它編譯時沒有任何警告和打印inf 好的,C ++可以處理除零,( 實時查看 )。

但,

案例2:

#include <iostream>

int main()
{
    double d = 15.50;
    std::cout<<(d/0)<<std::endl;
}

編譯器發出以下警告( 請參見實時 ):

warning: division by zero [-Wdiv-by-zero]
     std::cout<<(d/0)<<std::endl;

為什么編譯器會在第二種情況下發出警告?

0 != 0.0

編輯:

#include <iostream>

int main()
{
    if(0 == 0.0)
        std::cout<<"Same"<<std::endl;
    else
        std::cout<<"Not same"<<std::endl;
}

輸出:

Same

浮點除以零由IEEE很好地定義並給出無窮大(根據分子的值(或對於±0的NaN正或負)。

對於整數,沒有辦法表示無窮大,語言定義了具有未定義行為的操作,因此編譯器有助於引導您從該路徑中清除。

但是在這種情況下,由於分子是一個double ,因此除數( 0 )也應該被提升為double,並且沒有理由在這里發出警告而沒有給出0.0的警告,所以我認為這是一個編譯器錯誤。

在標准C ++中,兩種情況都是未定義的行為 可能發生任何事情,包括格式化硬盤。 你不應該期望或依賴“返回inf。好”或任何其他行為。

編譯器顯然決定在一個案例而不是另一個案例中發出警告,但這並不意味着一個代碼是好的而一個代碼沒有。 這只是編譯器生成警告的一個怪癖。

從C ++ 17標准[expr.mul] / 4:

二元/運算符產生商,二元%運算符從第一個表達式除以第二個表達式得到余數。 如果/%的第二個操作數為零,則行為未定義。

我回答這個特定問題的最佳猜測是編譯器執行int轉換為double 之前發出警告。

所以,步驟將是這樣的:

  1. 解析表達式
  2. 算術運算符 /(T, T2) ,其中T=doubleT2=int
  3. 檢查std::is_integral<T2>::value是否為trueb == 0 - 這會觸發警告。
  4. 發出警告
  5. 執行T2隱式轉換為double
  6. 執行定義明確的划分(因為編譯器決定使用IEEE 754)。

這當然是推測,並且基於編譯器定義的規范。 從標准的角度來看,我們正在處理可能的未定義行為。


請注意,根據GCC文檔 ,這是預期的行為
(順便說一下,似乎這個標志不能在GCC 8.1中明確使用)

-Wdiv被零
警告編譯時整數除以零。 這是默認值。 要禁止顯示警告消息,請使用-Wno-div-by-zero。 沒有警告浮點除零,因為它可以是獲得無窮大和NaN的合法方式。

在這個答案中,我不會進入UB /非UB的崩潰。

我只是想指出00.0 是不同的,盡管0 == 0.0評估為真。 0int literal, 0.0double literal。

但是在這種情況下,最終結果是相同的: d/0是浮點除法,因為d是double,因此0被隱式轉換為double。

我認為foo/0foo/0.0 一樣。 也就是說,第一個(整數除法或浮點除法)的結果效果高度依賴於foo的類型,而第二個(它將始終是浮點除法)則不是這樣。

兩者中的任何一個是UB是無關緊要的。 引用標准:

允許的未定義行為包括完全忽略不可預測的結果, 在翻譯或程序執行期間以環境特征(有或沒有發出診斷消息)的特定行為 ,終止翻譯或執行(發布時)一條診斷信息)。

(強調我的)

考慮“ 建議用作真值的賦值括號 ”警告:告訴編譯器你真的想要使用賦值結果的方法是明確,並在賦值周圍添加括號。 結果語句具有相同的效果,但它告訴編譯器您知道自己在做什么。 關於foo/0.0 :由於你通過使用0.0而不是0明確告訴編譯器“這是浮點除法”,編譯器會信任你並且不會發出警告。

這看起來像一個gcc bug, -Wno-div-by-zero的文檔清楚地說

不要警告編譯時整數除以零。 浮點除零不會被警告,因為它可以是獲得無窮大和NaN的合法方式。

[expr.arith.conv]中涵蓋的常用算術轉換后,兩個操作數都將加倍

許多期望算術或枚舉類型的操作數的二元運算符會以類似的方式引起轉換並產生結果類型。 目的是產生一個通用類型,它也是結果的類型。 這種模式稱為通常的算術轉換,定義如下:

...

- 否則,如果任一操作數為double,則另一個操作數應轉換為double。

[expr.mul]

*和/的操作數應具有算術或未范圍的枚舉類型; %的操作數應具有整數或無范圍的枚舉類型。 通常的算術轉換是在操作數上執行的,並確定結果的類型。

關於浮點除零是否是未定義的行為以及不同的實現如何處理它似乎是我的答案 TL; DR; 看起來gcc符合附件F中的浮點除以零,因此未定義在此處不起作用。 鏗鏘的答案會有所不同。

浮點除零的行為與整數除零的行為不同。

IEEE浮點標准區分+ inf和-inf,而整數不能存儲無窮大。 整數除零結果是未定義的行為。 浮點除以零由浮點標准定義,結果為+ inf或-inf。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM