2017-01-06 57 views
0

我一直在嘗試寫一些錯誤保護條款來識別第三方提供給我們的dll中的問題。這個dll可能有問題(內存異常,浮點錯誤等),並且能夠識別這些錯誤而無需訪問源代碼是有利的。如何在使用SEH時使用_controlfp_s?

我把各種SEH錯誤處理例程放在一起,但雖然它起作用,但它有幾個...不一致之處。我試圖隔離每一個,我將單獨提出一個問題。

這是使用_controlfp_s來設置和重置浮點錯誤行爲。

// For floating point protection --------- 
#include <float.h>  // defines of _EM_OVERFLOW, etc. 
#include <string.h>  // strncpy_s & strncat_s 
#include <stdlib.h>  // malloc 
#include <excpt.h>  // EXCEPTION_EXECUTE_HANDLER 
#include <iostream>  // cout 
#include <bitset>  // bitset 
#include <conio.h>  // _kbhit 
#pragma fenv_access (on) 
// --------------------------------------- 


const unsigned int SERIOUS_FP_EXCEPTIONS = _EM_DENORMAL | _EM_ZERODIVIDE | _EM_INVALID; 
const unsigned int MINOR_FP_EXCEPTIONS = _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT; 

int main(int argc, char[]) 
{ 
    double numerator = 1.0; 
    double denominator = 0.0; 
    double result = 0.0; 


    unsigned int _previous_floating_point_control; 
    unsigned int _current_floating_point_control; 

    _controlfp_s(&_current_floating_point_control, 0, 0); 
    std::cout << "Floating point word originally:  " << std::bitset<32>(_current_floating_point_control) << std::endl; 
    std::cout << "New settings to add:     " << std::bitset<32>(MINOR_FP_EXCEPTIONS) << std::endl; 
    std::cout << "With the mask:      " << std::bitset<32>(_MCW_EM) << std::endl; 

    _controlfp_s(&_previous_floating_point_control, MINOR_FP_EXCEPTIONS, _MCW_EM);  // This should appear to work, according to the documentation. 
    std::cout << "Floating point word cached:   " << std::bitset<32>(_previous_floating_point_control) << std::endl; 

    /* This works: 
    _controlfp_s(&_previous_floating_point_control, 0, 0);  // This should appear to work, according to the documentation. 
    _controlfp_s(nullptr, MINOR_FP_EXCEPTIONS, _MCW_EM);  // This should appear to work, according to the documentation. 
    std::cout << "Floating point word cached:   " << std::bitset<32>(_previous_floating_point_control) << std::endl; 
    */ 

    _controlfp_s(&_current_floating_point_control, 0, 0); 
    std::cout << "Floating point word used:    " << std::bitset<32>(_current_floating_point_control) << std::endl; 

    __try { 
     result = numerator/denominator; 
     _controlfp_s(NULL, _previous_floating_point_control, _MCW_EM); 
     std::cout << "No error detected." << std::endl; 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     std::cout << "Error code is:      " << std::bitset<32>(GetExceptionCode()) << std::endl; 
     if ((GetExceptionCode() & _EM_INVALID) || (GetExceptionCode() & _EM_ZERODIVIDE) || (GetExceptionCode() & _EM_DENORMAL)) 
      std::cout << "ERROR! Serious floating point error!" << std::endl; 
     else 
      std::cout << "Something else..." << std::endl; 

     _controlfp_s(NULL, _previous_floating_point_control, _MCW_EM); 

     _controlfp_s(&_current_floating_point_control, 0, 0); 
     std::cout << "Floating point word reset to:   " << std::bitset<32>(_current_floating_point_control) << std::endl; 

    } 

    std::cout << "result = " << result << std::endl; 

    while (!_kbhit()) // Wait until a key is pressed to close console. 
    { } 
} 

這將產生:

Floating point word originally:  00000000000010010000000000011111 
New settings to add:     00000000000000000000000000000111 
With the mask:      00000000000010000000000000011111 
Floating point word cached:   00000000000010010000000000000111 
Floating point word used:    00000000000010010000000000000111 
ERROR! Serious floating point error! 
Floating point word reset to:   00000000000010010000000000000111 
result = 0 

注意_previous_floating_point_control實際上是設置爲值,因此努力將其在最後復位沒有做任何事情。

這是正確的行爲(使用_controlfp_s兩個步驟):

Floating point word originally:  00000000000010010000000000011111 
New settings to add:     00000000000000000000000000000111 
With the mask:      00000000000010000000000000011111 
Floating point word cached:   00000000000010010000000000011111 
Floating point word used:    00000000000010010000000000000111 
ERROR! Serious floating point error! 
Floating point word reset to:   00000000000010010000000000011111 
result = 0 

我假定這是一個錯誤,因爲我有辦法解決它,我很高興地忽略它。但是,情況變得更糟:如果您注意到,上面的示例(其工作原理)將浮點單詞設置爲MINOR_FP_EXCEPTIONS,並且這會成功獲取SERIOUS_FP_EXCEPTIONS。如果我嘗試更換此:

_controlfp_s(&_previous_floating_point_control, SERIOUS_FP_EXCEPTIONS, _MCW_EM); 

產量:

Floating point word originally:  00000000000010010000000000011111 
New settings to add:     00000000000010000000000000011000 
With the mask:      00000000000010000000000000011111 
Floating point word cached:   00000000000010010000000000011111 
Floating point word used:    00000000000010010000000000011000 
No error detected. 
result = 1.#INF 


_controlfp_s(&_previous_floating_point_control, 0, _MCW_EM); 

產量:

Floating point word originally:  00000000000010010000000000011111 
New settings to add:     00000000000000000000000000000000 
With the mask:      00000000000010000000000000011111 
Floating point word cached:   00000000000010010000000000011111 
Floating point word used:    00000000000010010000000000000000 
Error code is:      11000000000000000000001010110101 
ERROR! Serious floating point error! 
Floating point word reset to:   00000000000010010000000000011111 
result = 0 

和: _controlfp_s(nullptr,_MCW_EM,_MCW_EM); 產量:

Floating point word originally:  00000000000010010000000000011111 
New settings to add:     00000000000010000000000000011111 
With the mask:      00000000000010000000000000011111 
Floating point word cached:   00000000000010010000000000011111 
Floating point word used:    00000000000010010000000000011111 
No error detected. 
result = 1.#INF 

因此,要總結:

  • _controlfp_s不「搞定」老浮點字的「設置」的副產品,但如果你在做單獨操作。
  • 要捕捉嚴重的浮點錯誤,您需要設置_controlfp_s來查找次要的f.p.e.s而不是主要的錯誤。
  • [未能識別除以零的問題是另一問題之一]

我只是誤解,這整個地區?

回答

0

我想我會對這個問題做出回答,因爲我已經對我的相關問題做了非常有用的迴應:How do I interpret GetExceptionCode results when using SEH?

通過實驗,似乎_controlfp_s的新設置是忽略的例外情況,而不是異常情況。我發現這個......的官方文件不清楚。

關於將舊值返回到f.p.的問題當設定一個新詞時:我相信這是一個錯誤 - 或者至少是不希望的行爲。該文檔明確指出,當掩碼爲0時,_controlfp_s將填充舊值,但不另外提及。在幾乎所有類似的功能中,我希望你能夠在一個操作中完成獲取和設置 - 而不是一個功能,它可以作爲獲取的集合。

相關問題