C लाइब्रेरी फ़ंक्शंस के पीछे तर्क कभी भी ग़लती से शून्य पर सेट नहीं होता है


9

C मानक अनिवार्य करता है कि कोई C मानक लाइब्रेरी फ़ंक्शन errnoशून्य पर सेट न हो। आखिर ऐसा क्यों है?

मैं इसे कई कार्यों को कॉल करने के लिए उपयोगी समझ सकता था, और केवल errnoपिछले एक के बाद जांच कर रहा था - उदाहरण के लिए:

errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
    // either "strtod" or "strtol" failed
else
    // both succeeded

हालांकि, यह "बुरा अभ्यास" नहीं माना जाता है? जब से तुम ही जाँच कर रहे हैं errnoअंत में, आप केवल कि कार्यों में से एक को पता किया था असफल, लेकिन नहीं जो ढंग से काम करते विफल रहा है। क्या केवल यह जानना कि अधिकांश व्यावहारिक कार्यक्रमों के लिए कुछ अच्छा पर्याप्त नहीं है?

मैंने विभिन्न C Rationale दस्तावेजों की तलाश की, लेकिन उनमें से कई के लिए बहुत अधिक विवरण नहीं है <errno.h>


1
मुझे लगता है कि यह "आप जो नहीं चाहते हैं उसके लिए भुगतान न करें"। यदि आप परवाह करते हैं errno, तो आप इसे हमेशा खुद को शून्य करने के लिए सेट कर सकते हैं।
केरेक एसबी

2
कुछ और पता होना चाहिए कि एक फ़ंक्शन errnoगैर-शून्य मान पर सेट हो सकता है, भले ही वह सफल हो। (यह कुछ अन्य फ़ंक्शन को विफल कर सकता है, लेकिन यह बाहरी फ़ंक्शन में विफलता का गठन नहीं करता है।)
कीथ थॉम्पसन

जवाबों:


10

सी लाइब्रेरी 1errno ऐतिहासिक कारणों से 0 पर सेट नहीं होती है । POSIX अब यह दावा नहीं करता है कि इसकी लाइब्रेरी सफलता के मामले में मूल्य में बदलाव नहीं करेगी, और इसके लिए नया लिनक्स मैन पेज :errno.h

<errno.h>हेडर फाइल पूर्णांक चर को परिभाषित करता है errno, जो सिस्टम कॉल और एक त्रुटि की स्थिति में कुछ पुस्तकालय कार्यों से संकेत मिलता है क्या गलत हुआ द्वारा निर्धारित है। इसका मूल्य तभी महत्वपूर्ण है जब कॉल के रिटर्न मूल्य में त्रुटि (यानी, -1अधिकांश सिस्टम कॉल से; -1या NULLअधिकांश पुस्तकालय कार्यों से) संकेत दिया गया हो ; एक फ़ंक्शन जो सफल होता है उसे बदलने की अनुमति है errno

एएनएसआई सी दलील कहा गया है कि समिति ने महसूस किया इसे अपनाने और उपयोग करने का मौजूदा प्रथा को मानकीकृत करने के लिए और अधिक व्यावहारिक था errno

सेटिंग के बारे में केंद्रित त्रुटि रिपोर्टिंग मशीनरी errnoको आमतौर पर सहिष्णुता के साथ सबसे अच्छा माना जाता है। इसमें लाइब्रेरी के कार्यों के बीच एक `` पैथोलॉजिकल युग्मन '' की आवश्यकता होती है और यह एक स्थिर लिखने योग्य मेमोरी सेल का उपयोग करता है, जो कि साझा करने योग्य पुस्तकालयों के निर्माण में हस्तक्षेप करता है। फिर भी, समिति ने इस मौजूदा, हालांकि कमी, मशीनरी का मानकीकरण करना पसंद किया, बजाय इसके कि कुछ और महत्वाकांक्षी का आविष्कार किया जाए।

यदि errnoसेट किया गया है तो जाँच के बाहर त्रुटि की जाँच करने का लगभग हमेशा एक तरीका है । यदि errnoसेट किया गया है तो हमेशा चेक करना विश्वसनीय नहीं होता है, क्योंकि कुछ कॉल में त्रुटि का कारण जानने के लिए अलग एपीआई की आवश्यकता होती है। उदाहरण के लिए, ferror()किसी त्रुटि के लिए जाँच करने के लिए उपयोग किया जाता है यदि आपको इससे कोई छोटा परिणाम मिलता है fread()या fwrite()

दिलचस्प रूप से पर्याप्त है, उपयोग करने strtod()का आपका उदाहरण उन मामलों में से एक है जहां errnoकॉल करने से पहले 0 पर सेट करना आवश्यक है, अगर त्रुटि हुई है तो सही ढंग से पता लगाने के लिए। सभी strto*()स्ट्रिंग टू नंबर फ़ंक्शंस की यह आवश्यकता होती है, क्योंकि एक त्रुटि के कारण भी एक वैध रिटर्न वैल्यू वापस आ जाती है।

errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
    /*...parse error */
} else if (errno == ERANGE) {
    if (x == 0) {
        /*...underflow */
    } else if (x == HUGE_VAL) {
        /*...positive overflow */
    } else if (x == -HUGE_VAL) {
        /*...negative overflow */
    } else {
        /*...unknown range error? */
    }
}

उपरोक्त कोड strtod()लिनक्स पर प्रलेखित व्यवहार के आधार पर है । सी मानक केवल उल्लेख है कि अधःप्रवाह एक मूल्य के अधिक से अधिक वापस नहीं लौट सकते छोटी से छोटी सकारात्मक की तुलना में double, और चाहे या नहीं errnoपर सेट है ERANGEहै कार्यान्वयन परिभाषित 2

वास्तव में एक व्यापक सर्टिफिकेट एडवाइजरी राइट-अप है जो errnoलाइब्रेरी कॉल से पहले हमेशा 0 पर सेट करने की सलाह देता है और कॉल फेल होने के बाद इसकी वैल्यू चेक करता है । ऐसा इसलिए है क्योंकि कुछ लाइब्रेरी कॉल सेट हो जाएंगी errnoभले ही कॉल 3 सफल हो ।

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


1. पहले मैंने दावा किया था कि यह एक पुराने कॉल से त्रुटि को रोकने के लिए था। मुझे इस दावे का समर्थन करने के लिए कोई सबूत नहीं मिला। मेरे पास एक फर्जी printf()उदाहरण भी था ।
2. इसे इंगित करने के लिए @chux को धन्यवाद। संदर्भ C.11 is7.22.1.3 §10 है।
3. एक टिप्पणी में @KeithThompson द्वारा इंगित किया गया।


माइनर समस्या: ऐसा प्रतीत होता है कि अंडरफ़्लो एक गैर-0 परिणाम हो सकता है: "फ़ंक्शन एक मान लौटाते हैं जिसकी परिमाण वापसी प्रकार में सबसे छोटे सामान्यीकृत सकारात्मक संख्या से अधिक नहीं है" C11 7.22.1.3.10।
चक्स -

@chux: धन्यवाद। मैं एक संपादन करूँगा। की स्थापना के बाद से errnoकरने के लिए ERANGEअधःप्रवाह के मामले में परिभाषित कार्यान्वयन किया जाता है, वहाँ वास्तव में कोई अधःप्रवाह पता लगाने के लिए पोर्टेबल तरीका है। मेरे कोड ने अपने सिस्टम पर लिनक्स मैन पेज में जो पाया, उसका पालन किया।
jxh

strto*फ़ंक्शंस के बारे में आपकी टिप्पणी ठीक इसी तरह है कि मैंने पूछा कि क्या मेरे उदाहरण को बुरा व्यवहार माना जाएगा, लेकिन यह एकमात्र तरीका है जिसमें errnoशून्य पर सेट नहीं किया जाना उपयोगी होगा, या यहां तक ​​कि लागू भी होगा।

@DrewMcGowen: मुझे लगता है कि केवल एक ही बिंदु जो आप ले सकते हैं वह यह है कि errnoसफलता के मामले में भी सेट हो सकता है, इसलिए बस सेट किए गए तथ्य का उपयोग करना वास्तव में एक अच्छा पर्याप्त संकेतक नहीं है कि एक त्रुटि हुई। आपको यह जानने के लिए व्यक्तिगत कॉल के परिणामों की जांच करनी होगी कि क्या त्रुटि हुई है।
jxh 8'13

1

यदि आप वास्तव में परवाह करते हैं, तो आप फ़ंक्शन कॉल के लिए त्रुटि जांच कर सकते हैं।

errno = 0;
double x = strtod(str1, NULL);
if (errno)
    // strtod"  failed
else
    // "strtod" succeeded

long y = strtol(str2, NULL);
if (errno)
    // "strtol" failed
else
    // "strtol" succeeded

चूँकि हमें कभी नहीं पता होता है कि कैसे एक प्रक्रिया में मच फंक्शन को बुलाया जाता है, तो प्रत्येक फंक्शन कॉल के लिए लिबास सेट कैसे हो सकता है?


1

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

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