我一直在嘗試寫一些錯誤保護條款來識別第三方提供給我們的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而不是主要的錯誤。
- [未能識別除以零的問題是另一問題之一]
我只是誤解,這整個地區?