2010-11-26 13 views
8

मैं विजुअल स्टूडियो (2005 या 2008) के तहत फ़्लोटिंग पॉइंट अपवादों को पकड़ने के लिए एक विश्वसनीय तरीका प्राप्त करने के लिए संघर्ष कर रहा हूं। डिफ़ॉल्ट रूप से, दृश्य स्टूडियो के तहत, फ्लोटिंग पॉइंट अपवादों को पकड़ा नहीं जाता है, और उन्हें पकड़ने में काफी मुश्किल होती है (मुख्य रूप से उनमें से अधिकांश हार्डवेयर सिग्नल होते हैं, और अपवादों में अनुवाद करने की आवश्यकता होती है)दृश्य सी ++/अजीब व्यवहार फ्लोटिंग-पॉइंट अपवाद (कंपाइलर बग?) सक्षम करने के बाद

यहां मैंने यह किया है:
- से निपटने
SEH अपवादों को चालू करें (गुण/कोड पीढ़ी/सक्षम सी ++ अपवाद: SEH अपवाद के साथ हाँ)
- सक्रिय चल

_controlfp का उपयोग कर मैं अब अपवाद (के रूप में नीचे दिखाए गए उदाहरण पकड़ने करते अपवाद बताते हैं जो शून्य अपवाद द्वारा एक सरल विभाजन)। हालांकि, जैसे ही मैं इस अपवाद को पकड़ता हूं, ऐसा लगता है कि कार्यक्रम अपरिवर्तनीय रूप से दूषित है (सरल फ्लोट प्रारंभिक होने के साथ-साथ std :: cout काम नहीं करेगा!)।

मैंने एक साधारण डेमो प्रोग्राम बनाया है जो यह अजीब व्यवहार दिखाता है।

नोट: यह व्यवहार कई कंप्यूटरों पर पुन: उत्पन्न किया गया था।

#include "stdafx.h" 
#include <math.h> 

#include <float.h> 
#include <iostream> 


using namespace std; 


//cf http://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP 
//cf also the "Numerical Recipes" book, which gives the same advice 
    //on how to activate fp exceptions 
void TurnOnFloatingExceptions() 
{ 
    unsigned int cw; 
    // Note : same result with controlfp 
    cw = _control87(0,0) & MCW_EM; 
    cw &= ~(_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW); 
    _control87(cw,MCW_EM); 

} 

//Simple check to ensure that floating points math are still working 
void CheckFloats() 
{ 
    try 
    { 
     // this simple initialization might break 
     //after a float exception! 
    double k = 3.; 
    std::cout << "CheckFloatingPointStatus ok : k=" << k << std::endl; 
    } 
    catch (...) 
    { 
    std::cout << " CheckFloatingPointStatus ==> not OK !" << std::endl; 
    } 
} 


void TestFloatDivideByZero() 
{ 
    CheckFloats(); 
    try 
    { 
    double a = 5.; 
    double b = 0.; 
    double c = a/b; //float divide by zero 
    std::cout << "c=" << c << std::endl; 
    } 
    // this catch will only by active: 
    // - if TurnOnFloatingExceptions() is activated 
    // and 
    // - if /EHa options is activated 
    // (<=> properties/code generation/Enable C++ Exceptions : Yes with SEH Exceptions) 
    catch(...) 
    {   
    // Case 1 : if you enable floating points exceptions ((/fp:except) 
    // (properties/code generation/Enable floting point exceptions) 
    // the following line will not be displayed to the console! 
    std::cout <<"Caught unqualified division by zero" << std::endl; 
    } 
    //Case 2 : if you do not enable floating points exceptions! 
    //the following test will fail! 
    CheckFloats(); 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    TurnOnFloatingExceptions(); 
    TestFloatDivideByZero(); 
    std::cout << "Press enter to continue";//Beware, this line will not show to the console if you enable floating points exceptions! 
    getchar(); 
} 

क्या किसी के पास इस स्थिति को ठीक करने के लिए क्या किया जा सकता है इस पर कोई संकेत है? अग्रिम में बहुत धन्यवाद!

उत्तर

10

जब आप फ़्लोटिंग पॉइंट अपवाद पकड़ते हैं तो आपको स्थिति शब्द में एफपीयू अपवाद झंडे को साफ़ करना होगा। कॉल _clearfp()।

एक अपवाद फ़िल्टर लिखने के लिए _set_se_translator() का उपयोग करने पर विचार करें जो हार्डवेयर अपवाद को C++ अपवाद में अनुवादित करता है। चुनिंदा होना सुनिश्चित करें, केवल एफपीयू अपवादों का अनुवाद करें।

+2

एक महत्वपूर्ण नोट, हालांकि: _fpreset() फ़्लोटिंग-पॉइंट स्टेटस शब्द को साफ़ करेगा * और * फ्लोटिंग-पॉइंट गणित पैकेज को फिर से शुरू कर देगा, यानी अपवादों को बाद में नहीं फेंक दिया जाएगा। बाद के अपवादों को अक्षम न करने के लिए, _clearfp() का उपयोग –

+0

के बजाय किया जा सकता है मुझे ओक्यू (इसलिए आप दोनों के लिए एक बड़ा +1) जैसी ही समस्या थी। –

1

अतिरिक्त जानकारी: यदि आप 64-बिट विंडो पर 32-बिट कोड चला रहे हैं, और/arch: SSE2 या अन्य विकल्प जो एसएसई 2 निर्देश सेट या उसके सुपरसेट्स को सक्षम करते हैं, तो आपको और अधिक करने की आवश्यकता हो सकती है कठोर रीसेट।

विजुअल स्टूडियो 2015 (और, संभवत: बाद के संस्करणों) के साथ, आपको _clepfet() के बजाय एसएसई 2 रजिस्टरों में उत्पन्न फ्लोटिंग-पॉइंट जाल के बाद _fpreset() को कॉल करने की आवश्यकता है। यदि आप इसे विजुअल स्टूडियो 2013 और इससे पहले करते हैं, तो आपको कई प्रकार की अजीब समस्याएं मिलती हैं, जो रन-टाइम लाइब्रेरी भ्रमित हो जाती है।

संबंधित मुद्दे