2010-12-15 11 views
15

मैं सी ++ घटक डीएल विकसित कर रहा हूं जिसका उपयोग सी या सी ++ अनुप्रयोगों द्वारा किया जा सकता है। उजागर dll कार्यों के रूप में इस प्रकार हैक्या सी प्रोग्राम प्रोग्राम C++ अपवादों को संभाल सकता है?

#include <tchar.h> 
#ifdef IMPORT 
#define DLL __declspec(dllimport) 
#else 
#define DLL __declspec(dllexport) 
#endif 

extern "C" { 

    DLL bool __cdecl Init(); 
    DLL bool __cdecl Foo(const TCHAR*); 
    DLL bool __cdecl Release(); 

} 

इन कार्यों के आंतरिक कार्यान्वयन जो उजागर नहीं कर रहे हैं सी ++ वर्ग हैं मैं इस शैली dll या तो सी या सी ++ क्षुधा में इस्तेमाल किया जा सकता का उपयोग कर मान रहे हैं। समस्या यह है कि मैं किसी भी प्रकार के C++ अपवाद (यानी bad_alloc) को संभाल नहीं पाता हूं और मैंने यह सामान कॉलर (उच्च परत) पर छोड़ा है। मेरे सहयोगियों के साथ बहुत बहस के बाद मुझे सभी अपवादों को पकड़ना चाहिए और त्रुटि कोड या कम से कम झूठी वापसी करनी चाहिए क्योंकि सी आवेदन के मामले में यह सी ++ अपवादों को संभाल नहीं सकता है? क्या यह सच है? और मुझे सामान्य रूप से क्या करना चाहिए? यदि आप घटक विकसित कर रहे हैं जो अन्य सिस्टम द्वारा उपयोग किया जाएगा तो exeptions को संभालने के लिए अंगूठे का एक नियम है।

+1

नहीं, सी – sje397

+0

में अपवाद जैसी कोई चीज़ नहीं है http://www.on-time.com/ddj0011.htm – DumbCoder

+3

सी ++ सी पंजीकृत कर सकता है 'std :: set_unexpected()' के माध्यम से बिना अपवादों के अपवाद हैंडलर के लिए अपवाद हैंडलर के रूप में -लिंक/'बाहरी सी' फ़ंक्शन। यदि उस के लिए उलझन वाला नाम ज्ञात है तो आप इसे सीधे सादे सी से कॉल कर सकते हैं। अन्यथा, आप 'बाहरी सी' का पर्दाफाश कर सकते हैं इसके लिए रैपर। यह नहीं कि यह एक सुविधाजनक इंटरफ़ेस है, लेकिन यदि यह पूरी तरह से अपरिहार्य है कि आपकी लाइब्रेरी अपनी सीमाओं के बाहर प्रदूषित है ... –

उत्तर

16

सी में अपवाद नहीं हैं, इसलिए सामान्य रूप से आपको सभी अपवादों को पकड़ना चाहिए और एक त्रुटि कोड वापस करना चाहिए और/या एक त्रुटि प्रदान करना जो अंतिम त्रुटि के बारे में जानकारी देता है।

+0

"सी में अपवाद नहीं हैं"। क्यों नहीं; सी ++ रनटाइम में अपवाद हैं, और सी ++ रनटाइम में सी इंटरफेसिंग में सी ++ रनटाइम है, तो सी अपवादों के विशिष्ट कार्यान्वयन के लिए सी ++ रनटाइम को क्यों रोक नहीं सकता है (विभिन्न प्रणालियों में अलग-अलग कार्यान्वयन हो सकते हैं, लेकिन कार्यान्वयन अभी भी मौजूद है और इसमें मौजूद होना चाहिए स्मृति, और यहां तक ​​कि यदि यह खुलासा नहीं किया गया है, तो आप इसे समझने और विभिन्न बाइट्स को पोक करने और अप्रत्याशित कार्यों को कॉल करने के लिए स्मृति का विश्लेषण कर सकते हैं)। – Dmitry

18

यदि यह एमएसवीसी का उपयोग कर विंडोज है तो हाँ आप सी में अपवाद पकड़ सकते हैं लेकिन आप उन्हें अच्छी तरह से पकड़ नहीं सकते हैं। सी ++ अपवाद ओएस एबीआई के संरचित अपवाद हैंडलिंग तंत्र के माध्यम से खिलाए जाते हैं, और माइक्रोसॉफ्ट के पास ओएस संरचित अपवादों को संभालने के लिए __try, __except, __finally सी एक्सटेंशन है। ध्यान दें कि इनमें एक्सेस उल्लंघन, विभाजन-दर-शून्य इत्यादि शामिल हैं, जिन्हें आप आम तौर पर अपने प्रोग्राम को समाप्त करना चाहते हैं और एक बग रिपोर्ट लॉग करना चाहते हैं। आप कोड 0xE04D5343 (4 डी 53 43 = "एमएससी") द्वारा सी ++ अपवादों की पहचान कर सकते हैं और बाकी को फेंक सकते हैं।

सभी ने कहा कि, शायद आप एक डीएलएल सीमा में अपवाद फेंकना नहीं चाहते हैं, और निश्चित रूप से नहीं कि आप केवल सी एपीआई का पर्दाफाश कर रहे हैं।

+0

ठीक है, लेकिन अगर मैं डीएल का ग्राहक सी ++ ऐप्स है, तो क्या डीएल सीमा में अपवादों को प्रसारित करना अच्छा विचार है? –

+1

@ अहमद: नहीं, जब तक कि आप वहां प्रत्येक कंपाइलर संस्करण के लिए डीएलएल वितरित नहीं करना चाहते हैं। –

+0

@ अहमद: इस मामले में, मैं कहूंगा कि यह है, लेकिन फिर यह आसान है -> यदि आप सी-इंटरफेस प्रदान करते हैं तो अपवादों का उपयोग न करें, अगर आप सी ++ इंटरफ़ेस प्रदान करते हैं, तो आप कर सकते हैं। –

7

कॉलर को केवल उन्हें संभालने के लिए डिज़ाइन किया गया है तो कॉलर को अपवादों का प्रचार करें। मुझे लगता है कि आपके मामले में terminate() तुरंत कॉल किया जाएगा जब कोई अपवाद सी ++ कोड से बच निकलता है क्योंकि सी ++ रनटाइम के बिंदु से अपवाद को संभाला नहीं गया है।

समान सर्वर COM सर्वर डिज़ाइन में उत्पन्न होता है - ग्राहक जो भी भाषा/तकनीक में हो सकते हैं। फैसले यह है कि COM सर्वर विधियों से बचने के लिए कोई अपवाद नहीं होना चाहिए - सभी अपवादों को HRESULT में पकड़ा जाना चाहिए और (वैकल्पिक रूप से) IErrorInfo। आपको अपनी परिस्थितियों में भी ऐसा ही करना चाहिए।

यदि सी कोड को ++ कोड propagating exceptions to C code is still a very bad idea की दो परतों के बीच सैंडविच किया गया है।

11

एक सामान्य नियम के रूप में, आप कभी नहीं सी ++ अपवाद एक मॉड्यूल के सीमा से परे प्रचार करने के लिए अनुमति चाहिए। ऐसा इसलिए है क्योंकि सी ++ मानक निर्दिष्ट नहीं करता है कि अपवाद प्रसार कैसे कार्यान्वित किया जाना चाहिए, और इस तरह यह संकलक (और कंपाइलर झंडे) और ऑपरेटिंग सिस्टम निर्भर है। आप गारंटी नहीं दे सकते कि आपके मॉड्यूल को कॉल करने वाले कोड को आपके मॉड्यूल के समान कंपेलर झंडे के साथ एक ही कंपाइलर के साथ संकलित किया जाएगा। वास्तव में, जैसा कि आप इस प्रश्न के साथ प्रदर्शित कर रहे हैं यह है कि आप गारंटी नहीं दे सकते कि आपके मॉड्यूल को कॉल करने वाले कोड को उसी भाषा में लिखा जाएगा।

अधिक जानकारी के लिए, कृपया Sutter और Alexandrescu द्वारा C++ कोडिंग मानकों में आइटम 62 देखें।

8

ठीक है, के बाद से यह करने के लिए कहा गया था:

सी ++ उदाहरण कोड:

#include <typeinfo> 
#include <exception> 
extern "C" { 
void sethandler(void (*func)(void)) { std::set_terminate(func); } 
int throwingFunc(int arg) { 
    if (arg == 0) 
     throw std::bad_cast(); 
    return (arg - 1); 
} 
} 

सी उदाहरण कोड:

#include <stdio.h> 

extern int throwingFunc(int arg); 
extern void sethandler(void (*func)(void)); 

void myhandler(void) 
{ 
    printf("handler called - must've been some exception ?!\n"); 
} 

int main(int argc, char **argv) 
{ 
    sethandler(myhandler); 

    printf("throwingFunc(1) == %d\n", throwingFunc(1)); 
    printf("throwingFunc(-1) == %d\n", throwingFunc(-1)); 
    printf("throwingFunc(0) == %d\n", throwingFunc(0)); 
    return 0; 
} 

जब मैं इन दो संकलन, उन्हें एक साथ लिंक और इस चलाते हैं (उबंटू 10.04, जीसीसी 4.4.5, x64), मुझे मिलता है:

$ ./xx 
throwingFunc(1) == 0 
throwingFunc(-1) == -2 
handler called - must've been some exception ?! 
Aborted 

तो जब आप सी से पकड़ अपवाद कर सकते हैं, यह शायद ही पर्याप्त है - क्योंकि std::terminate() के बाद सी ++ रनटाइम व्यवहार अनिर्धारित है, और क्योंकि हैंडलर को कोई भी स्थिति जानकारी नहीं मिलती है (अपवाद प्रकारों और/या स्रोतों को दूर करने के लिए)। हैंडलर कुछ भी साफ नहीं कर सकता है।

बीटीडब्ल्यू, मैंने जानबूझकर std::bad_cast() को इस उदाहरण में अपवाद प्रकार के रूप में चुना है। ऐसा इसलिए है क्योंकि फेंकने से std::set_unexpected() और std::set_terminate() के बीच व्यवहार में अंतर दिखाई देता है - अप्रत्याशित हैंडलर को सभी अप std::bad_* अपवादों के लिए बुलाया जाएगा, जबकि मानक अपवादों को पकड़ने के लिए, एक समाप्ति हैंडलर की आवश्यकता है ... दुविधा देखें? व्यावहारिक उपयोग होने के लिए दोहन बहुत व्यापक है :(

+0

असल में ऐसा करने में बिंदु केवल उपयोगकर्ता को निरस्त करने से पहले एक त्रुटि संदेश प्रदान करना है। मुद्दा यह है कि पकड़ा जाना चाहिए क्या पकड़ा जाना चाहिए, और शेष अपवादों के लिए, यथासंभव वर्णनात्मक हो। –

+0

यही कारण है कि मैं "दुविधा" कहता हूं - आप अपवाद को पकड़ सकते हैं और एक त्रुटि लॉग कर सकते हैं, लेकिन कितना वर्णनात्मक _as वर्णनात्मक है? इस तथ्य से कि हैंडलर को कोई संदर्भ नहीं दिया गया है, मैं कहूंगा "बहुत नहीं" ... –

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