2010-07-26 9 views
9

पर पोर्ट करना मेरे पास एक हजार-लाइन एप्लिकेशन है जो SIGFPE पर निर्भर करता है (सिग्नल() को पारित फ़ंक्शन पॉइंटर द्वारा नियंत्रित) राज्य को बदलने के लिए और जब कुछ फ़्लोटिंग पॉइंट स्थितियां होती हैं तो कोड सही ढंग से चलाया जाता है। हालांकि, प्रबंधित मोड में सी ++/सीएलआई के तहत, _control87 एक सिस्टम उत्पन्न करता है। सी _ _ppreset और _control87 में लिखे गए एक स्थिर lib में निष्पादित एर्थिथमिक एक्सेप्शन समर्थित नहीं है।सी ++/सीएलआई: एसआईजीएफपीई, _control87, _fpreset, प्राचीन अप्रबंधित वाटकॉम सी ऐप को .NET

मैं क्लासिक, अप्रबंधित SIGFPE ऑपरेशन को सी ++/सीएलआई एप्लिकेशन में काम करने के लिए कैसे प्राप्त करूं? मेरे आवेदन में फ्लोटिंग प्वाइंट स्टफ्स की जगहों की संख्या बहुत अधिक हो सकती है और मैं कई प्रोग्रामर द्वारा लिखे गए सभी संख्यात्मक तरीकों को पूरी तरह से समझ नहीं पा रहा हूं।

मैं पुराने स्कूल अपवाद हैंडलिंग को एक फ्लोटिंग पॉइंट डिवीजन पर शून्य से काम करना चाहता हूं, आईएनएफ मूल्य नहीं। प्लेटफार्म का आह्वान शैली काम नहीं करती है, और #pragma प्रबंधित (बंद) चाल भी नहीं करता है।

मेरे पास कौन से विकल्प हैं?

+0

क्या यह काम करता है जब आप बिना/clr संकलित करते हैं? क्या आप अपने अन्य प्रबंधित कोड को कॉल करने के लिए ऐप को/क्लियर भाग में विभाजित कर सकते हैं (या आपके लिए प्रबंधित सामग्री को कॉल करने के लिए) और मूल भाग SIGPFE के साथ? या वे भी उलझन में हैं? –

+0

मेरे पास शुद्ध सी इंटरैस के माध्यम से सी # इंटरऑप के साथ एक समान स्थिति है। मेरे पास कोई सी ++/सीएलआई कोड नहीं है, मेरा सभी सी ++ कोड अप्रबंधित है। मैं एसआईजीएफपीई के लिए अपना कॉलबैक पंजीकृत करता हूं (अप्रबंधित कोड के लिए कॉलस्टैक प्राप्त करने का प्रयास कर रहा हूं), लेकिन .NET रनटाइम हमेशा मेरे सिग्नल फ़ंक्शन को कॉल करने के बजाय एरिथमेटिक अपवाद को ओवरराइड करता है और फेंकता है। – zahir

उत्तर

4

यहां कई गंभीर दर्द बिंदु हैं। फ़्लोटिंग पॉइंट अपवादों को सक्षम करना प्रबंधित कोड निष्पादन के साथ काफी असंगत है। मूल बातें नीचे, आप आसानी से जेआईटी-कंपाइलर को दुर्घटनाग्रस्त कर सकते हैं। जब आप _control87() का उपयोग करते हैं तो आप किस समस्या से जूझ रहे हैं।

और हाँ, आपको एक सीएलआर अपवाद मिलेगा, जब भी यह मूल कोड निष्पादित करता है तो यह अपवाद बैकस्टॉप रखता है। एक सिग्नल हैंडलर केवल तब ही बुलाया जाता है जब अपवाद उठाया जाता है और इसे संभालने के लिए कोई कोड नहीं होता है। अनिवार्य रूप से सी रनर सी रनटाइम लाइब्रेरी इसे देख सकने से पहले अपवाद देखता है। तो आपको कभी भी SIGFPE हैंडलर कॉल नहीं मिलेगा।

इस पर शॉट करने का एकमात्र सभ्य तरीका एक रैपर लिखना है जो सीएलआर के पहले अपवाद को पकड़ता है। साथ ही, बहुत महत्वपूर्ण है कि आप सावधानीपूर्वक एफपीयू नियंत्रण शब्द का प्रबंधन करते हैं, आप देशी कोड चलते समय केवल एफपीयू अपवाद सक्षम कर सकते हैं। यह किरकिरा कोड का एक गुच्छा लेता है, ऊपर की चेतावनी है कि आप इसका आनंद लेने के लिए नहीं जा रहे हैं।

आप किसी भी टुकड़ा पोस्ट नहीं तो मैं एक मूर्खतापूर्ण उदाहरण बनाने के लिए होगा:

#include <Windows.h> 
#include <signal.h> 
#include <float.h> 

#pragma managed(push, off) 

double divisor; 

void __cdecl fpehandler(int sig) { 
    divisor = 1.0; 
} 

double badmath() { 
    divisor = 0.0; 
    return 1/divisor; 
} 
#pragma managed(pop) 

आदेश fpehandler() प्राप्त करने के लिए कहा जाता है, आप सी क्रम अंदर अपवाद संचालक कॉल करने की आवश्यकता पुस्तकालय। सौभाग्य से यह सामने आ रहा है और आप इसे लिंक कर सकते हैं, आप केवल एक घोषणा की आवश्यकता है इसलिए आप इसे कॉल कर सकते हैं के लिए:

// Exception filter in the CRT, it raises the signal 
extern "C" int __cdecl _XcptFilter(unsigned long xcptnum, 
            PEXCEPTION_POINTERS pxcptinfoptrs); 

आपको यह सुनिश्चित करना है कि यह केवल कभी चल बिन्दु अपवाद के लिए कहा जाता है बनाने की जरूरत है।)

int FloatingpointExceptionFilter(unsigned long xcptnum, PEXCEPTION_POINTERS pxcptinfoptrs) { 
    // Only pass floating point exceptions to the CRT 
    switch (xcptnum) { 
     case STATUS_FLOAT_DIVIDE_BY_ZERO: 
     case STATUS_FLOAT_INVALID_OPERATION: 
     case STATUS_FLOAT_OVERFLOW: 
     case STATUS_FLOAT_UNDERFLOW: 
     case STATUS_FLOAT_DENORMAL_OPERAND: 
     case STATUS_FLOAT_INEXACT_RESULT: 
     case STATUS_FLOAT_STACK_CHECK: 
     case STATUS_FLOAT_MULTIPLE_TRAPS: 
     case STATUS_FLOAT_MULTIPLE_FAULTS: 
      return _XcptFilter(xcptnum, pxcptinfoptrs); 
      break; 
     default: 
      return EXCEPTION_CONTINUE_SEARCH; 
    } 
} 

अब आप badmath (के लिए एक आवरण लिख सकते हैं कि संकेत हैंडलर कहा जाता हो जाता है:

double badmathWrapper() { 
    __try { 
     return badmath(); 
    } 
    __except (FloatingpointExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { 
    } 
} 

कौन सा बारी में कहा जा सकता है तो हम एक आवरण है कि अपवाद कोड की ओर ध्यान देता जरूरत एक सी ++/सीएलआई कक्षा द्वारा जिसे आप किसी भी प्रबंधित कोड से कॉल कर सकते हैं। यह सुनिश्चित करना है कि चल बिन्दु अपवाद कॉल करने से पहले सक्षम है और कॉल के बाद फिर से बहाल कर रहे हैं की जरूरत है:

using namespace System; 
using namespace System::Runtime::CompilerServices; 

public ref class Wrapper { 
public: 
    static double example(); 
}; 

[MethodImplAttribute(MethodImplOptions::NoInlining)] 
double Wrapper::example() { 
    signal(SIGFPE, fpehandler); 
    _clear87(); 
    unsigned oldcw = _control87(_EM_INEXACT, _MCW_EM); 
    try { 
     return badmathWrapper(); 
    } 
    finally { 
     _control87(oldcw, _MCW_EM); 
     signal(SIGFPE, nullptr); 
    } 
} 

नोट कॉल _control87 करने के लिए(), यह सिवाय "अयथार्थ परिणाम" सभी अस्थायी अपवाद सक्षम बनाता है। कोड को जब्त करने की अनुमति देना आवश्यक है। यदि आप इसे मुखौटा नहीं करते हैं तो सीएलआर एक भयानक मौत की मृत्यु हो जाती है, जब तक इस साइट का नाम खत्म नहीं हो जाता है तब तक अपवाद फेंक देते हैं। उम्मीद है कि आपके सिग्नल हैंडलर को इसकी आवश्यकता नहीं है।

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