[英]How to catch divide-by-zero error in Visual Studio 2008 C++?
如何在 Visual Studio 2008 C++ 中捕獲被零除錯誤(而不是其他錯誤;並且能夠訪問異常信息)?
我試過這個:
try {
int j=0;
int i= 1/j;//actually, we call a DLL here, which has divide-by-zero
} catch(std::exception& e){
printf("%s %s\n", e.what());
} catch(...){
printf("generic exception");
}
但這適用於通用的 ... catch 塊。 我知道特定於 MS 的 __try 在這里可能很有用,但我更喜歡標准 C++,並且無論如何我都有阻止使用 __try 的析構函數。
澄清:為了討論目的,上面的代碼被簡化了。 實際上,被零除是一個錯誤,它發生在我沒有源代碼的第三方 DLL 深處。 錯誤取決於我傳遞給庫的參數(復雜結構的句柄),但不是以任何明顯的方式。 所以,我希望能夠優雅地恢復。
C++ 本身不會將被零除作為異常處理。
引用 Stroustrup 的話:
“低級事件,例如算術溢出和被零除,假定由專用的低級機制處理,而不是由異常處理。這使 C++ 在算術方面能夠匹配其他語言的行為。它還避免了在大量流水線架構上發生的問題,在這些架構中,諸如除以零之類的事件是異步的。”
“C++ 的設計和演變”(Addison Wesley,1994 年)
在任何情況下,例外情況是從來沒有進行適當的處理的前提條件更換。
要在 Visual C++ try->catch (...) 中捕獲除以零異常,只需在項目設置中啟用 /EHa 選項即可。 請參閱項目屬性 -> C/C++ -> 代碼生成 -> 將 Enable C++ Exceptions 修改為“Yes With SEH Exceptions” 。 而已!
在此處查看詳細信息: http : //msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
假設您不能簡單地修復異常生成代碼的原因(可能是因為您沒有該特定庫的源代碼,也可能是因為您無法在輸入參數引起問題之前對其進行調整)。
您必須跳過一些障礙才能按照您的意願完成這項工作,但它可以完成。
首先,您需要通過調用_set_se_translator()
(參見此處)來安裝結構化異常處理轉換函數,然后您可以檢查在發生 SEH 異常時傳遞的代碼並拋出適當的 C++ 異常。
void CSEHException::Translator::trans_func(
unsigned int code,
EXCEPTION_POINTERS *pPointers)
{
switch (code)
{
case FLT_DIVIDE_BY_ZERO :
throw CMyFunkyDivideByZeroException(code, pPointers);
break;
}
// general C++ SEH exception for things we don't need to handle separately....
throw CSEHException(code, pPointers);
}
然后你可以簡單地在 C++ 中以正常方式捕獲你的CMyFunkyDivideByZeroException()
。
請注意,您需要在要轉換異常的每個線程上安裝異常轉換功能。
您可以使用結構化異常處理(使用 __try 等),也可以安裝結構化異常處理程序轉換器: _set_se_translator
這兩者都是特定於操作系統的。
您不能使用標准 C++ 做到這一點,因為它不是標准 C++ 異常。 這是一個結構化的例外。 對於標准的 C++ 異常,必須有人throw exception;
從代碼。
為什么不先檢查一下? 與用於異常處理的上下文切換相比,簡單j == 0
的性能將是微不足道的。
試試下面的代碼:
try
{
const int j=0;
if (j == 0) { throw std::exception("j was 0"); }
const int i= 1/j;
}
catch(std::exception& e)
{
printf("%s %s\n", e.what());
}
catch(...)
{
printf("generic exception");
}
當然,如果你可以毫無例外地這樣做,你可以這樣做:
const int j = 0;
if (j == 0)
{
/* do something about the bad pre-condition here */
}
else
{
const int i = 1 / j;
}
為回應澄清而進行編輯:您必須弄清楚您將哪些輸入交給第三方,導致它們事先被零除,並在調用它們的函數之前處理它。
一個好的方法是使用安全的面向對象的包裝器,如SafeInt 。 它似乎也集成在 Visual Studio 2010 中。
更新:
如果被零除發生在第三方代碼中,您唯一的選擇是 SEH 或Seb Rose 回答的等效內容
您可以使用try-except Statement 。 但是,不要忘記您需要為每個線程設置它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.