2013-11-10 7 views
6

मैं perror() या strerror() "मानव पठनीय" त्रुटि एक errno से संबंधित संदेश है, लेकिन क्या मुद्रित करने के लिए उपयोग कर सकते हैं, तो मैं भीerrno का प्रतीक नाम (जैसे, "EAGAIN") प्रिंट करना चाहते हैं ?मैं सी में इरनो के प्रतीकात्मक नाम को कैसे मुद्रित कर सकता हूं?

ऐसा करने के लिए कोई सुविधाजनक फ़ंक्शन या मैक्रो?

अद्यतन: कोड मैं लेखन समाप्त हो गया संलग्न, अपनी टिप्पणी नीचे स्वीकार किए जाते हैं जवाब और के विचार पर आधारित:

#include <ctype.h> 
#include <errno.h> 
#include <stdio.h> 

int get_errno_name(char *buf, int buf_size) { 
    // Using the linux-only gawk instead of awk, because of the convenient 
    // match() functionality. For Posix portability, use a different recipe... 
    char cmd[] = "e=  && " // errno to be inserted here (max digits = 6) 
       "echo '#include <errno.h>' | " 
       "gcc -dM -E - | " // optionally, use $CC inead of gcc 
       "gawk \"match(\\$0, /^#[[:space:]]*define[[:space:]]+" 
        "(E[[:alnum:]]+)[[:space:]]+$e($|[^[:alnum:]])/, m) " 
        "{ print m[1] }\""; 
    { 
     // Insert the errno as the "e" shell variable in the command above. 
     int errno_digit_c = snprintf(cmd + 2, 6, "%d", errno); 
     if (errno_digit_c < 1) { 
      fprintf(stderr, "Failed to stringify an errno " 
          "in get_errno_name().\n"); 
      return -1; 
     } 
     // Replace the inserted terminating '\0' with whitespace 
     cmd[errno_digit_c + 2] = ' '; 
    } 
    FILE *f = popen(cmd, "r"); 
    if (f == NULL) { 
     perror("Failed to popen() in get_errno_name()"); 
     return -1; 
    } 
    int read_size = 0, c; 
    while ((c = getc(f)) != EOF) { 
     if (isalnum(c)) { 
      buf[read_size++] = c; 
      if (read_size + 1 > buf_size) { 
       fprintf(stderr, "Read errno name is larger than the character " 
           "buffer supplied to get_errno_name().\n"); 
       return -1; 
      } 
     } 
    } 
    buf[read_size++] = '\0'; 
    if (pclose(f) == -1) { 
     perror("Failed to pclose() in get_errno_name()"); 
     return -1; 
    } 
    return read_size; 
} 
+0

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

+0

@ जोनाथन लेफ्लर आपकी प्रतिक्रिया के लिए धन्यवाद। दोनों खातों पर सहमत मुझे शायद यह उल्लेख करना चाहिए था कि उपर्युक्त निश्चित रूप से इस तरह तैनात नहीं किया जाना चाहिए (जब तक कि आप दोनों जीसीसी और गॉक पर रन-टाइम निर्भरता नहीं मानते ...)। और हाँ; इस तरह का कोड संकलित समय पर (सी) स्क्रिप्ट बनाने के हिस्से के रूप में बेहतर होगा। हालांकि मेरी परियोजनाएं छोटी होती हैं, इसलिए मैं आमतौर पर ऐसी स्क्रिप्ट से परेशान नहीं होता; यही कारण है कि उपरोक्त कोड मेरे व्यक्तिगत डीबग बिल्ड के लिए मुझे सबसे अच्छा लगा। – Will

उत्तर

4

ऐसा करने का कोई आसान तरीका नहीं है।

आप एक प्रोग्राम बना सकते हैं - और मैंने एक बनाया है, जिसे लाइब्रेरी फ़ंक्शन के रूप में पुन: संग्रहित किया जा सकता है - जो संख्या से नाम में परिवर्तित हो जाता है। लेकिन तालिका उत्पन्न करना मामूली मुश्किल है। मैं एक पर्ल स्क्रिप्ट का उपयोग करता हूं जो /usr/include/errno.h समेत हेडर सूचीबद्ध करने के लिए विकल्पों (-H) के साथ कंपाइलर (जीसीसी या समतुल्य) चलाता है, और फिर उन फ़ाइलों को स्कैन करता है, नामों की तलाश में (#define प्लस E के बाद ऊपरी केस अक्षर या अंक), संख्याएं, और टिप्पणियां। यह लिनक्स, मैक ओएस एक्स, सोलारिस, एचपी-यूएक्स, एईक्स पर काम करता है। यह विशेष रूप से तुच्छ नहीं है।

खबरदार, मैक ओएस एक्स पर errno.h एक नाम ELAST (एक नाम कार्यान्वयन का उपयोग करने के लिए आरक्षित) सबसे अधिक संख्या में (लेकिन रिलीज से मानचित्रण परिवर्तन को रिहा करने का डुप्लिकेट है कि शामिल है, यह पर्वत शेर में 105 था , मेरा मानना ​​है, लेकिन यह मैवेरिक्स में 106 है)।

+1

'echo' # शामिल '| $ सीसी-डीएम-ई - | grep -E '^ # [[: space:]] * परिभाषित करें [[: space:]] + E'' –

+0

@R ..: अधिक या कम, हाँ, लेकिन यदि आप इसे उपयोगी रूप से संकलित करने जा रहे हैं, तो आप प्रतीकात्मक नाम को एक स्ट्रिंग में परिवर्तित करना होगा, और संभावित रूप से टिप्पणी को कैप्चर करना होगा (हालांकि आप त्रुटि संदेश भाग को संभालने के लिए 'strerror()' का उपयोग कर सकते हैं, आदि –

+0

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

2

मेरी जानकारी आप नहीं कर सकते करने के लिए। कुछ पूर्णांक त्रुटि स्थिरांक किसी एक से अधिक प्रतीकात्मक नाम पर मैप किए जाते हैं उदा। EAGAIN और EWOULDBLOCK। जाहिर है आप उन्हें आदेश के मैन पेज पर देख सकते हैं जो त्रुटि सेट करता है।

+1

ईगल और इडौल्डब्लॉक केवल दो ही हैं जो समान हो सकते हैं। अन्य सभी के पास अलग-अलग मूल्य होना चाहिए। –

+1

EDEADLK और EDEADLOCK भी लिनक्स पर – Duck

+0

पॉज़िक्स [''] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html) एक जोड़ी के रूप में EAGAIN और EWOULDBLOCK सूचीबद्ध करता है, लेकिन ENOTSUP और EOPNOTSUPP । प्लेटफॉर्म में अन्य डुप्लिकेट नाम हो सकते हैं। चूंकि आपको किसी दिए गए नंबर के लिए केवल एक नाम की आवश्यकता है, इसलिए आप एक को वैधानिक नाम के रूप में चुन सकते हैं। –

0

मुझे ऐसा कोई फ़ंक्शन नहीं पता है जो ऐसा करता है, लेकिन यदि आप अपने प्रोग्राम में लौट रहे त्रुटियों से परिचित हैं तो इसे लिखना मुश्किल नहीं होगा।

आप स्ट्रिंग्स() के आउटपुट वाले स्ट्रिंग्स लिख सकते हैं और लूप के लिए उपयोग कर सकते हैं और यदि आपके द्वारा लिखे गए तारों की तुलना करने के लिए strcmp() (जो सफलता या विफलता के आधार पर मूल्य देता है) के साथ कथन का उपयोग करते हैं। यदि वे वही हैं तो आप प्रतीकात्मक नाम * आउटपुट कर सकते हैं यदि आप इसे किसी अन्य स्ट्रिंग पर सेट करते हैं।

+0

आपको 'strerror' के आउटपुट के खिलाफ 'strcmp' क्यों करना होगा? – Leigh

+0

आप उन्हें errno.h में देख सकते हैं और उस पर आधारित कुछ लिख सकते हैं। यह काम करेगा ... जब तक ऐसा नहीं होता क्योंकि कुछ बदल गया है। – Duck

1

आप जानते हैं कि त्रुटियों आप उम्मीद कर रहे हैं, तो आप errno के खिलाफ बड़ा switch/case या if/else ब्लॉक लिख सकता है निम्नलिखित शैली में,:

if (errno == EAGAIN) 
    fprintf(stderr, "EAGAIN"); 

इस के साथ स्पष्ट समस्या यह है कि आप विशिष्ट errno चाहते हैं 'नाम', आपको प्रत्येक संभावित विकल्प के खिलाफ लिखने की ज़रूरत है, और वहां कुछ हैं।

+0

यह बहुत सामान्य नहीं है। कम से कम एक फ़ंक्शन बनाएं जो तारों की सरणी का उपयोग करता है, और संख्या के अनुरूप नाम पर 'char const *' देता है। –

0

चूंकि प्रतीकात्मक नाम गणना के रूप में संग्रहीत किए जाते हैं और C उन्हें Ints के रूप में व्यवहार करता है। आपको इस SO प्रश्न How to convert enum names to string in c के समान फ़ंक्शन बनाना होगा। आप शायद इसे मैक्रो को आसानी से कम कर सकते हैं लेकिन प्रत्येक त्रुटि के लिए एक केस बनाना होगा।

+2

सी मानक (सी 99, कम से कम) कहता है कि 'ई *' स्थिरांक मैक्रोज़ हैं, गणना नहीं। – jwodder

+0

ठीक है, जीएनयू कंपाइलर उन पर स्विच करता है और उन्हें enums के रूप में व्यवहार करता है। भ्रामक जानकारी के लिए मैं क्षमा चाहता हूं। –

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

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