सी में अपवाद कैसे फेंकें?


100

मैंने इसे Google में टाइप किया, लेकिन केवल C ++ में हॉवोस पाया,

इसे C में कैसे करें?


6
C अपवाद से निपटने का समर्थन नहीं करता है। C में एक अपवाद को फेंकने के लिए, आपको कुछ विशिष्ट प्लेटफ़ॉर्म का उपयोग करने की आवश्यकता है जैसे कि Win32 का संरचित अपवाद हैंडलिंग - लेकिन इसके साथ कोई भी सहायता देने के लिए, हमें उस प्लेटफ़ॉर्म को जानना होगा जिसकी आपको परवाह है।
जेरी कॉफिन

18
... और Win32 संरचित अपवाद हैंडलिंग का उपयोग न करें।
ब्रायन आर। बॉन्डी

4
सेटजम्प () और लॉन्गजम्प () का उपयोग, सिद्धांत रूप में, काम करना चाहिए, लेकिन मुझे नहीं लगता कि यह परेशानी के लायक है।
जोसेफ क्विन्से

जवाबों:


77

सी में कोई अपवाद नहीं हैं। सी में त्रुटियों को फ़ंक्शन के लौटाए गए मूल्य, प्रक्रिया के निकास मूल्य, प्रक्रिया के संकेतों ( प्रोग्राम त्रुटि सिग्नल (GNU libc) ) या सीपीयू हार्डवेयर रुकावट (या अन्य अधिसूचना) द्वारा अधिसूचित किया जाता है। यदि सीपीयू है तो त्रुटि उत्पन्न होती है) ( कैसे प्रोसेसर शून्य से विभाजन के मामले को संभालता है )।

अपवादों को C ++ और अन्य भाषाओं में परिभाषित किया गया है। C ++ में एक्सेप्शन हैंडलिंग C ++ मानक "S.15 एक्सेप्शन हैंडलिंग" में निर्दिष्ट है, C मानक में कोई समान खंड नहीं है।


4
तो सी में यह गारंटी है कि अपवाद नहीं होंगे, कैसे?
httpinterpret

62
@httpinterpret: सी में यह "गारंटीकृत" है कि इसमें कोई अपवाद नहीं हैं कि यह "गारंटीकृत" है कि कोई टेम्पलेट नहीं है, या कोई प्रतिबिंब नहीं है, या कोई गेंडा नहीं है। भाषा विनिर्देश केवल ऐसी किसी भी चीज़ को परिभाषित नहीं करता है। सेटजम्प / लॉन्गजम्प है, हालांकि, जिसका उपयोग बिना वापस आए किसी फ़ंक्शन से बाहर निकलने के लिए किया जा सकता है। इसलिए यदि वे चाहें तो कार्यक्रम स्वयं के अपवाद जैसे तंत्र का निर्माण कर सकते हैं या सी कार्यान्वयन मानक के विस्तार को परिभाषित कर सकता है।
स्टीव जेसोप

2
के साथ एक कार्यक्रम mainएक में .cफ़ाइल, कुछ सी ++ शामिल कर सकते हैं और इसलिए अपवाद फेंक दिया जा सकता है और इस कार्यक्रम में फंस गए, लेकिन सी कोड अंश यह है कि अपवाद फेंकने को छोड़कर चल रहा के सभी से अनभिज्ञ बनी रहती है और पकड़ने अक्सर सी में लिखे कार्यों पर भरोसा करते हैं जो C ++ पुस्तकालयों में रहता है। C का उपयोग किया जाता है क्योंकि आप फ़ंक्शन throwको एक अपवाद को फेंकने की आवश्यकता के लिए जोखिम नहीं उठा सकते हैं । हालांकि, अपवादों को फेंकने / पकड़ने के लिए एक संकलक / पुस्तकालय / लक्ष्य विशिष्ट तरीका हो सकता है। लेकिन एक वर्ग उदाहरण फेंकने से खुद को परेशानी होगी।
nategoose

61
@Steve: कृपया मुझे बताएं कि अगर आपको इकसिंगों के साथ कोई भाषा मिलती है, तो मैं वर्षों से इस तरह की प्रतीक्षा कर रहा हूं।
ब्रायन आर। बॉन्डी

5
@ BrianR.Bondy यहां इकसिंगों के साथ एक भाषा है (मैं इसे उसी तरह से गारंटी देता हूं जैसे कि सी में इसकी गारंटी है)
टॉफैंडेल

37

सी में आप setjmp()और longjmp()परिभाषित कार्यों के संयोजन का उपयोग कर सकते हैं setjmp.hउदाहरण विकिपीडिया से

#include <stdio.h>
#include <setjmp.h>

static jmp_buf buf;

void second(void) {
    printf("second\n");         // prints
    longjmp(buf,1);             // jumps back to where setjmp 
                                //   was called - making setjmp now return 1
}

void first(void) {
    second();
    printf("first\n");          // does not print
}

int main() {   
    if ( ! setjmp(buf) ) {
        first();                // when executed, setjmp returns 0
    } else {                    // when longjmp jumps back, setjmp returns 1
        printf("main");         // prints
    }

    return 0;
}

नोट: मैं वास्तव में आपको सलाह दूंगा कि आप इनका उपयोग करें क्योंकि वे C ++ के साथ भयानक काम करते हैं (स्थानीय वस्तुओं के विनाशकों को नहीं बुलाया जाएगा) और यह समझना मुश्किल है कि क्या चल रहा है। इसके बजाय किसी प्रकार की त्रुटि लौटाएं।


मैंने देखा है setjump / longjump C ++ प्रोग्राम में सही ढंग से काम नहीं करता है, यहां तक ​​कि जब अपवाद का उपयोग किए जाने पर विनाश की आवश्यकता नहीं थी। मैं शायद ही कभी सी कार्यक्रमों में उनका उपयोग करता हूं।
nategoose

यह सेटजम्प का उपयोग करते हुए एक दिलचस्प दृष्टिकोण था। on-time.com/ddj0011.htm लेकिन हाँ, मूल रूप से आपको उन्हें स्वयं ही इनवॉइस करना होगा यदि आप स्टैक को अनइंस्टॉल किए बिना आउट-ऑफ-बैंड कोड निष्पादन चाहते हैं।
ड्वेन रॉबिन्सन

मुझे यकीन नहीं है कि C ++ में उनका उपयोग करने के बारे में चेतावनी क्यों है जब सवाल C और C ++ के बारे में है, वैसे भी अपवाद हैं। किसी भी मामले में, यह महत्वपूर्ण है कि ओपी जानता है कि सेटपम्प / लॉन्गजम्प कार्यान्वयन को अपने पैर की शूटिंग से दूर रखने के लिए, हमेशा ध्यान रखें कि आपको सबसे पहले त्रुटि हैंडलर (इसे सेट करने के लिए) और उस त्रुटि हैंडलर पर जाने की आवश्यकता है दो बार लौटने की जरूरत है।

1
वैसे, अपवाद हैंडलिंग कुछ ऐसी चीज थी जिसकी मैं वास्तव में उम्मीद कर रहा था कि वह C11 में समाप्त हो जाएगी। आम धारणा के बावजूद, इसे ठीक से काम करने के लिए ओओपी की आवश्यकता नहीं होती है, और सी को प्रत्येक फ़ंक्शन कॉल की आवश्यकता होती है if()। मैं इसमें कोई खतरा नहीं देख सकता; यहाँ कोई और हो सकता है?

@ user4229245 मैं (एक विशेष) धारणा के तहत "कुछ भी किया है" आपके लिए किया गया है "सी भाषा की कल्पना से बाहर रखा गया है जितना संभव हो विशेष रूप से नंगे धातु और मशीन प्रोग्रामिंग के लिए सी प्रासंगिक रखने के लिए जहां आठ योजन दूर की तरह यथास्थिति बुनियादी बातों में भी है। टी यूनिवर्सल, सिर्फ मेरे विचार थो, मैं कोई विशेष लेखक नहीं हूँ
थोरसुमोनर

21

सादा पुराना सी वास्तव में मूल रूप से अपवादों का समर्थन नहीं करता है।

आप वैकल्पिक त्रुटि हैंडलिंग रणनीतियों का उपयोग कर सकते हैं, जैसे:

  • त्रुटि कोड वापस करना
  • FALSEएक last_errorचर या फ़ंक्शन का उपयोग करके वापस लौटना ।

Http://en.wikibooks.org/wiki/C_Programming/Error_handling देखें ।


इसके अलावा विंडोज़ एपी में इरोस को संभालने के लिए एक ही तरीका है। उदाहरण के लिए GetLastError()विंडोज़ एपीआई में।
BattleTested

20

सी में कोई अंतर्निहित अपवाद तंत्र नहीं है; आपको अपवादों और उनके शब्दार्थों का अनुकरण करने की आवश्यकता है । यह आमतौर पर setjmpऔर पर भरोसा करके हासिल किया जाता है longjmp

आसपास काफी पुस्तकालय हैं, और मैं अभी तक एक और को लागू कर रहा हूं। इसे अपवाद 4c कहा जाता है ; यह पोर्टेबल और मुफ्त है। आप इसे देख सकते हैं, और अन्य विकल्पों के खिलाफ तुलना करके देख सकते हैं कि कौन सा आपको सबसे अधिक पसंद है।


मैंने आपको कोड उदाहरण पढ़ा, मैंने एक संरचना के साथ इसी तरह की परियोजना शुरू की, लेकिन प्रत्येक "अपवाद" की पहचान करने के लिए एक स्ट्रिंग के बजाय एक यूआईडी का उपयोग करता है। आपकी परियोजना बहुत आशाजनक है।
umlcat

विकल्प लिंक अब इंगित करना चाहिए github.com/guillermocalvo/exceptions4c/wiki/alternatives
मार्सेल Waldvogel

क्या आप (या कोई और) विभिन्न अपवाद पैकेजों के बीच तुलना के बारे में जानते हैं?
मार्सेल वाल्डवोगेल

11

C C ++ अपवाद को फेंकने में सक्षम है, वे वैसे भी मशीन कोड हैं। उदाहरण के लिए, bar.c में

// begin bar.c
#include <stdlib.h>
#include <stdint.h>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
   int64_t * p = (int64_t*)__cxa_allocate_exception(8);
   *p = 1976;
   __cxa_throw(p,&_ZTIl,0);
  return 10;
}
// end bar.c

in.cc,

#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
  try{
    bar1();
  }catch(int64_t x){
    printf("good %ld",x);
  }
}
int main(int argc, char *argv[])
{
  foo();
  return 0;
}

संकलन करने के लिए

gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out

उत्पादन

good 1976

http://mentorembedded.github.io/cxx-abi/abi-eh.html के बारे में अधिक विस्तार से जानकारी है __cxa_throw

मुझे यकीन नहीं है कि यह पोर्टेबल है या नहीं, और मैं इसे 'gcc-4.8.2' के साथ लिनक्स पर परीक्षण करता हूं।


2
क्या है "_ZTIl" ??? मुझे कहीं भी इसका कोई संदर्भ नहीं मिल रहा है और यह एक पूर्ण रहस्य है कि यह कैसे संभव होगा कि सी कोड के लिए std :: type_ffo तक पहुंच हो। कृपया मेरी मदद करें!
AreusAstarte

1
_ZTIIसाधन typeinfo for long, जैसे echo '_ZTIl' | c++filt । यह जी ++ प्रबंध योजना है।
9

और सिर्फ अच्छे उपाय के लिए c ++ से बचने के लिए कैच ब्लॉक में ac सिंबल बुलाना सुनिश्चित करें: P (PS एक उत्कृष्ट वास्तविक उदाहरण साझा करने के लिए आपका धन्यवाद!)
ThorSummoner

8

यह सवाल सुपर पुराना है, लेकिन मैं अभी इसके पार गया और सोचा कि मैं एक तकनीक साझा करूंगा: शून्य से विभाजित करें, या एक शून्य सूचक को निष्क्रिय करें।

सवाल बस "कैसे फेंकना है", न कि कैसे पकड़ना है, या एक विशेष प्रकार के अपवाद को कैसे फेंकना है। मेरे पास एक ऐसी स्थिति थी, जहां हमें C ++ में पकड़े जाने के लिए C से एक अपवाद को ट्रिगर करने की आवश्यकता थी। विशेष रूप से, हमारे पास "शुद्ध आभासी फ़ंक्शन कॉल" त्रुटियों की कभी-कभार रिपोर्ट थी, और कुछ को फेंकने के लिए सी रनटाइम के _purecall फ़ंक्शन को समझाने की आवश्यकता थी। इसलिए हमने अपने स्वयं के _purecall फ़ंक्शन को जोड़ा, जो शून्य से विभाजित होता है, और बूम होता है, हमें एक अपवाद मिला जिसे हम C ++ पर पकड़ सकते हैं, और यहां तक ​​कि कुछ स्टैक मस्ती का उपयोग करके देख सकते हैं कि चीजें कहां गलत हुईं।


@AreusAstarte बस के मामले में किसी को वास्तव में एक सी डिवीजन-बाय-शून्य दिखाया जाना चाहिए:int div_by_nil(int x) { return x/0; }

7

MSVC के साथ जीत पर वहाँ __try ... __except ...वास्तव में भयानक है और आप इसका उपयोग नहीं करना चाहते हैं यदि आप संभवतः इससे बच सकते हैं। यह कहना बेहतर है कि कोई अपवाद नहीं हैं।


1
वास्तव में सी ++ अपवाद एसईएच के शीर्ष पर भी हुड के नीचे बनाए गए हैं।
कैलमेरियस जूल

@ कल्मष क्या है SEH ?
मार्सेल वाल्डवोगेल

1
@MarcelWaldvogel संरचित अपवाद हैंडलिंग (CPU अपवादों को संभालने के लिए Windows का तरीका)।
कैलमेरियस

6

C में अपवाद नहीं हैं।

विभिन्न हैके कार्यान्वयन हैं जो इसे करने की कोशिश करते हैं (उदाहरण के लिए: http://adomas.org/excc/ )।


3

जैसा कि कई सूत्र में बताया गया है, ऐसा करने का "मानक" तरीका सेटजम्प / लॉन्गजम्प का उपयोग कर रहा है। मैंने अभी तक https://github.com/psevon/exception-and-raii-in-c पर इस तरह का एक और समाधान पोस्ट किया है, यह मेरे ज्ञान का एकमात्र समाधान है जो आवंटित संसाधनों के स्वचालित सफाई पर निर्भर करता है। यह अद्वितीय और साझा किए गए स्मार्टपॉइंटर्स को लागू करता है, और मध्यवर्ती कार्यों को अपवादों को पकड़ने के बिना गुजरने देता है और अभी भी अपने स्थानीय रूप से आवंटित संसाधनों को ठीक से साफ करता है।


2

C अपवादों का समर्थन नहीं करता है। आप अपने सी कोड को विजुअल स्टूडियो या जी ++ के साथ सी ++ के रूप में संकलित करने की कोशिश कर सकते हैं और देख सकते हैं कि क्या यह संकलन है। अधिकांश सी एप्लिकेशन प्रमुख परिवर्तनों के बिना C ++ के रूप में संकलित करेंगे, और आप तब कोशिश कर सकते हैं ... सिंटैक्स को पकड़ें।


0

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

int process(int port)
{
    int rc;
    int fd1;
    int fd2;

    fd1 = open("/dev/...", ...);
    if (fd1 == -1) {
      rc = -1;
      goto out;
    }

    fd2 = open("/dev/...", ...);
    if (fd2 == -1) {
      rc = -1;
      goto out;
    }

    // Do some with fd1 and fd2 for example write(f2, read(fd1))

    rc = 0;

   out:

    //if (rc != 0) {
        (void)close(fd1);
        (void)close(fd2);
    //}

    return rc;
}

यह वास्तव में हैंडलर को अपवाद नहीं करता है, लेकिन यह आपको fucntion निकास पर त्रुटि को संभालने का एक तरीका है।

पुनश्च आप केवल एक या अधिक गहरी स्कैप से ही गोटो का सावधानीपूर्वक उपयोग करें और कभी भी चर घोषणा न करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.