2012-07-10 21 views
9

सामान्य स्थिति में open() नई फ़ाइल डिस्क्रिप्टर को वापस करें, या -1 यदि कोई त्रुटि हुई और उस स्थिति में, errno उचित रूप से सेट किया गया है।क्यों fopen() या open() त्रुटि कोड लौटने के बजाय इरनो का उपयोग करें?

मुझे समझ में नहीं आ रहा है कि errno का यह तंत्र यहां क्यों उपयोग किया जाता है? यहाँ का उद्देश्य क्या है? क्यों हम कुछ नकारात्मक वापसी संख्या के साथ सभी त्रुटि मैप नहीं कर सकते हैं?

तरह

fd = open("/dev/tty0", O_RDWR | O_SYNC); 
if(fd == -1) 
    printf("this is EACCES error"); 
else if (fd == -2) 
    printf("this is EPERM error"); 

वहाँ errno तंत्र के किसी भी लाभ है।? यदि हां तो मैं अन्य चीजों में जानना/समझना चाहता हूं, मैं इस तंत्र का भी उपयोग कर सकता हूं।

उत्तर

11

fopen के बाद से रिटर्न एक FILE* आप वर्तमान अर्थ विज्ञान के साथ, आप एक सार्वभौमिक पैटर्न को अपनाने कर सकते हैं उस सूचक में त्रुटि कोड वापस करने की उम्मीद नहीं कर सकता: पॉइंटर्स के लिए केवल "विशेष" मान 0 है।

जैसा कि आप देखते हैं, open के लिए यह प्रतिबंध नहीं है। वास्तव में लिनक्स के रूप में सिस्टम ठीक वही करते हैं जो आप अपने निचले स्तर पर प्रस्तावित करते हैं। यदि चीजें गलत होती हैं तो हुड के तहत सिस्टम कॉल नकारात्मक त्रुटि कोड देता है। उस (अस्वीकृत) कोड को errno में उथले उपयोगकर्ता स्पेस रैपर द्वारा प्लग किया जाता है जो तब आवेदन में त्रुटि इंगित करने के लिए -1 देता है।

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

यह आदर्श नहीं है, लेकिन ओवरहेड उतना बुरा नहीं है जितना लगता है, क्योंकि ये स्पष्ट रूप से त्रुटि संकेत हैं जो केवल असाधारण रूप से होने चाहिए।

+0

+1 बहुत अच्छा जवाब है –

1

errno एक त्रुटि कोड है। वास्तव में क्या हो रहा है, इसकी त्रुटियों को मैप करना महत्वपूर्ण है ताकि आप अपने कोड में रणनीतिक निर्णय ले सकें कि आगे क्या करना है। उदाहरण के लिए, ERANGE जिसे errno.h में परिभाषित किया गया है, आपको बताएगा कि strtol("0xfffffffff",NULL,0) का परिणाम उस फ़ंक्शन की सीमा से बाहर है। आपके उदाहरण में अधिक महत्वपूर्ण बात यह जानना अच्छा है कि आपके पास EACCES या EPERM त्रुटि है ताकि आप फ़ाइल को कैसे संभालें।

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

इरनो इंस्टॉलेशन और त्रुटि प्रबंधन तंत्र का उपयोग ताकि आपको केवल -1 से अधिक जानकारी मिल सके।

ERANGE, EACCES, EPERM, और अन्य को मैक्रोज़ माना जाता है जो सुविधाजनक उद्देश्यों के लिए किसी विशेष त्रुटि संख्या पर नक्शा लगाते हैं।

9

मेरे लिए लाभ यह है कि हो रही त्रुटि जानकारी है कि रास्ते में एकीकृत है, लौटने में कुछ नकारात्मक मूल्य open साथ ठीक काम करेगा के रूप में यह एक पूर्णांक देता है, लेकिन fopen रिटर्न एक FILE * तो एक और तकनीक वहाँ इस्तेमाल किया जा करना होगा।

+0

FILE * अभी भी कुछ बफर/मेमोरी के लिए सूचक है, इसलिए यह कभी नकारात्मक नहीं होगा, इसलिए अगर त्रुटि हुई तो क्या हम नकारात्मक मूल्य के साथ FILE * वापस नहीं करते? क्योंकि NULL 0 –

+6

एक पॉइंटर है - कम से कम आर्किटेक्चर पर मुझे पता है - हस्ताक्षर की कोई अवधारणा नहीं है, यह (सैद्धांतिक रूप से) "अंतर्निहित हस्ताक्षरित पूर्णांक" की पूरी श्रृंखला को कवर कर सकती है (यानी 32 बिट बिंदु 0x00000000 से 0xffffffff तक जा सकता है) । और 'नूल' सिर्फ यह कहने का संकेत है कि "अरे, यह असफल रहा, यह देखने के लिए गलती हुई कि क्या गलत हुआ" – fvu

+0

सिद्धांत रूप में आरक्षित पॉइंटर्स का एक सेट भी इस्तेमाल किया जा सकता है; यह सब आवश्यक है 'char err_ptrs [MAX_ERRNO]; शून्य * EACCESS_ptr = err_ptrs + EACCESS; 'आदि। 'EACCESS_ptr' को पॉइंटर्स के लिए वैध" त्रुटि कोड "बनाने के लिए। हालांकि, उन्हें पूर्णांक और पॉइंटर्स के रूप में डुप्लिकेट करना है, और तथ्य यह है कि कुछ इंटरफ़ेस पूर्ण रिटर्न के रूप में पूर्णांक मानों की पूरी जगह का उपयोग करते हैं, फिर भी यह गलत साबित होता है। –

1

प्रत्येक फ़ंक्शन को रिटर्न मानों का एक अलग सेट देने से यह सामान्य जेनेरिक कोड में कोड लिखने के लिए अत्यधिक जटिल हो जाता है।

int fd; 
if ((fd = some_function(arg1, arg2)) == -1) 
{ 
    perror("some_function"); 
    exit(1); 
} 

तुम भी एक मैक्रो में इस लपेट कर सकते हैं::

#define CALL_OR_DIE(function, ret, ...)  \ 
    if ((ret = function(__VA_ARGS__)) == -1) \ 
    { perror(#function); exit(1); } 

उपयोग:

int fd; 
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC); 
+1

तो आप मूल रूप से कह रहे हैं (1) '<=' से '== -1' लिखना बेहतर है (गलत होने के लिए परिभाषित त्रुटियों के साथ), और (2) यह' errno' के लिए प्रेरणा है? मुझे लगता है कि विफलता मामले में 'fd' से' perror' को पास करने में कोई लाभ नहीं है, क्योंकि इसे थ्रेड-लोकल 'errno' से पढ़ा जा सकता है, लेकिन मुझे नहीं लगता कि यह पूरी तरह से बताता है कि इरनो क्यों नहीं है 'ओपन' से भी वापस नहीं आया। –