2011-03-09 14 views
25

मैंने एक सूचनात्मक आलेख पर ठोकर खाई: http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ जिसने मैक्रोज़ मैक्रोज़ के अपने वर्तमान सूट में मौजूद बड़ी संख्या में समस्याओं को इंगित किया।कस्टम सी ++ जोर दें मैक्रो

मैक्रो के अंतिम संस्करण के लिए पूर्ण कोड लेख के अंत के पास दिया जाता है यदि आप लिंक का पालन करें।

के रूप में प्रस्तुत सामान्य रूप (किसी ने मुझसे सही करें अगर मैं इसे सुर में गलत हूँ) इस तरह है:

#ifdef DEBUG 
#define ASSERT(cond) \ 
    do \ 
    { \ 
     if (!(cond)) \ 
     { \ 
      ReportFailure(#cond, __FILE__, __LINE__, 0); \ 
      HALT(); \ 
     } \ 
    } while(0) 
#else 
#define ASSERT(cond) \ 
    do { (void)sizeof(cond); } while(0) 

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

एक था कि आप त्रिगुट ऑपरेटर (यानी cond?ASSERT(x):func()) के साथ इस मैक्रो का उपयोग नहीं कर सकते हैं, और सुझाव के रूप में त्रिगुट ऑपरेटर के साथ if() और कुछ कोष्ठकों को बदलने के लिए भी था अल्पविराम ऑपरेटर। एक और टिप्पणीकार पर बाद में इस जानकारी का स्रोत:

#ifdef DEBUG 
#define ASSERT(x) ((void)(!(x) && assert_handler(#x, __FILE__, __LINE__) && (HALT(), 1))) 
#else 
#define ASSERT(x) ((void)sizeof(x)) 
#endif 

मैं तार्किक के उपयोग के बारे में सोचा और && इस मामले में विशेष रूप से चालाक है और मुझे लगता है इस संस्करण एक if या यहाँ तक कि त्रिगुट ?: का उपयोग कर से अधिक लचीला है कि। यहां तक ​​कि अच्छा है कि assert_handler का वापसी मूल्य यह निर्धारित करने के लिए उपयोग किया जा सकता है कि कार्यक्रम रोकना चाहिए या नहीं। हालांकि मुझे यकीन नहीं है कि यह HALT() की बजाय (HALT(), 1) क्यों है।

क्या यहां दूसरे संस्करण के साथ कोई विशेष कमी है जिसे मैंने अनदेखा किया है? यह मैक्रोज़ के चारों ओर लिपटे do{ } while(0) से दूर है लेकिन यह अनावश्यक लगता है क्योंकि हमें if से निपटने की आवश्यकता नहीं है।

आपको क्या लगता है?

+1

+1। दिलचस्प लिंक – Maxpm

+0

नीचे मेरा उत्तर भी देखें: http://stackoverflow.com/a/21827201/216063 –

उत्तर

26

सी और सी ++ मानक पुस्तकालय में, assert एक मैक्रो है जिसे फ़ंक्शन के रूप में कार्य करने की आवश्यकता होती है। उस आवश्यकता का एक हिस्सा यह है कि उपयोगकर्ता इसे अभिव्यक्ति में उपयोग करने में सक्षम होना चाहिए। उदाहरण के लिए, मानक assert साथ मैं

int sum = (assert(a > 0), a) + (assert(b < 0), b); 

जो कार्यात्मक रूप

assert(a > 0 && b < 0) 
int sum = a + b; 

ही भले ही पूर्व एक बहुत अच्छा तरीका है एक अभिव्यक्ति लिखने के लिए नहीं हो सकता है कर सकते हैं, चाल अभी भी बहुत है कई और उचित मामलों में उपयोगी।

यह तुरंत कि अपने स्वयं के कस्टम ASSERT मैक्रो मानक assert व्यवहार और प्रयोज्य नकल करने के लिए करता है, तो चाहता है, तो ASSERT की परिभाषा में if या do { } while (0) का उपयोग कर सवाल से बाहर है का मतलब है। एक उस मामले में अभिव्यक्तियों तक ही सीमित है, जिसका अर्थ है ?: ऑपरेटर या शॉर्ट सर्किटिंग लॉजिकल ऑपरेटरों का उपयोग करना।

बेशक, अगर एक एक मानक की तरह कस्टम ASSERT बनाने के बारे में परवाह नहीं करता है, तो एक कुछ भी उपयोग कर सकते हैं, if भी शामिल है। लिंक्ड आलेख इस मुद्दे पर भी विचार नहीं करता है, जो कि अजीब है। मेरी राय में, एक फ़ंक्शन-जैसे जोर मैक्रो निश्चित रूप से गैर-फ़ंक्शन-जैसा एक से अधिक उपयोगी है।

(HALT(), 1) के लिए ... ऐसा इसलिए किया जाता है क्योंकि && ऑपरेटर को एक वैध तर्क की आवश्यकता होती है। HALT() का वापसी मूल्य && के लिए मान्य तर्क का प्रतिनिधित्व नहीं कर सकता है। यह मुझे पता है कि void हो सकता है, जिसका मतलब है कि केवल HALT() बस && के तर्क के रूप में संकलित नहीं होगा। (HALT(), 1) हमेशा 1 का मूल्यांकन करता है और इसमें int टाइप है, जो हमेशा && के लिए एक वैध तर्क है। तो, HALT() के प्रकार के बावजूद && के लिए (HALT(), 1) हमेशा वैध तर्क है।

do{ } while(0) के बारे में आपकी आखिरी टिप्पणी अधिक समझ में नहीं आती है। do{ } while(0) में मैक्रो को संलग्न करने का बिंदु बाहरी if एस से निपटना है, मैक्रो परिभाषा के अंदर if एस नहीं। आप हमेशा को बाहरी if से निपटना होगा, क्योंकि हमेशा एक मौका है कि आपका मैक्रो बाहरी if में उपयोग किया जाएगा। बाद की परिभाषा में do{ } while(0) की आवश्यकता नहीं है क्योंकि वह मैक्रो अभिव्यक्ति है। और एक अभिव्यक्ति होने के नाते, यह पहले से ही स्वाभाविक रूप से बाहरी if एस के साथ कोई समस्या नहीं है। इसलिए, उनके बारे में कुछ भी करने की ज़रूरत नहीं है। इसके अलावा, जैसा कि मैंने उपर्युक्त कहा है, इसे do{ } while(0) में संलग्न करना पूरी तरह से अपने उद्देश्य को पराजित करेगा, इसे एक गैर-अभिव्यक्ति में बदल देगा।

+2

"मेरी राय में, एक फ़ंक्शन-जैसे जोर मैक्रो निश्चित रूप से गैर-फ़ंक्शन-जैसा एक से अधिक उपयोगी है।" - क्यों? यह हर उपयोगी कब होता है? मुझे लगता है कि दावे हमेशा कोड में अकेले खड़े रहना चाहिए और अभिव्यक्तियों में कभी भी इस्तेमाल नहीं किया जाना चाहिए। –

+0

मैं कहूंगा कि यह बेहतर है क्योंकि अभिव्यक्ति में अभिव्यक्ति के साथ-साथ ठेठ "अकेले खड़े" तरीके में उपयोग करने योग्य _able_ है। उपयोगकर्ता के लिए अधिक विकल्प। @AndreyT, क्रिस्टल को इस भेद को स्पष्ट करने के लिए धन्यवाद, जिस पर मैं ग्लेज़ेड हूं। यह पहली बार बहुत अच्छा लग रहा था, लेकिन अब ऐसा प्रतीत होता है कि '{{} जबकि {0)' निर्माण बहुत उपयोगी नहीं है। सच्चाई यह है कि, मैं कुछ मैक्रोज़ का उपयोग कर रहा था जिसमें एक बड़ा 'अगर' कथन नहीं था, जो इस बिंदु पर स्पष्ट रूप से सही काम नहीं करता है। –

6

हालांकि मुझे यकीन है कि क्यों यह (HALT(), 1) के बजाय सिर्फ HALT() है नहीं कर रहा हूँ।

मैं कल्पना HALTexit के लिए एक मैक्रो (या अन्य स्टैंड में नाम) हो सकता है। मान लें कि हम exit(1) का उपयोग हमारे HALT कमांड के लिए करना चाहते थे। exitvoid देता है, जिसे && पर दूसरे तर्क के रूप में मूल्यांकन नहीं किया जा सकता है। यदि आप अल्पविराम ऑपरेटर का उपयोग करते हैं, जो इसके पहले तर्क का मूल्यांकन करता है, तो उसके दूसरे तर्क के मूल्य का मूल्यांकन और रिटर्न देता है, हमारे पास एक पूर्णांक (1) && पर वापस लौटने के लिए है, भले ही हम उस बिंदु तक कभी न पहुंचें क्योंकि HALT() हमें रोक देगा बहुत पहले तो।

असल में, HALT के लिए भरने वाले किसी भी फ़ंक्शन को शायद void का वापसी मूल्य होने वाला है, क्योंकि इससे कोई मूल्य वापस लौटने की कोई आवश्यकता नहीं होगी। हम इसे मैक्रो के लिए सिर्फ int वापस कर सकते हैं, लेकिन अगर हम पहले से ही मैक्रो के साथ हैकिंग कर रहे हैं तो थोड़ा और हैकर चोट नहीं पहुंचा सकता है, है ना?

+1

तो यह कंपाइलर को खुश करने और साइड इफेक्ट के रूप में बाहर निकलने का तरीका था (प्रोग्राम को समाप्त करना! काफी साइड इफेक्ट मुझे कहना चाहिए) इसे वापस करने का मूल्य देकर। साफ। –

8

पूर्णता के लिए के लिए, मैं प्रकाशित एक ड्रॉप में 2 फ़ाइलें सी में मैक्रो कार्यान्वयन पर जोर ++:

Assertion 'v > min && v < max' failed (DEBUG) 
    in file e.cpp, line 8 
    function: int main() 
    with message: invalid value: 2.000000, must be between 0.000000 and 1.000000 

Press (I)gnore/Ignore (F)orever/Ignore (A)ll/(D)ebug/A(b)ort: 

कहाँ

  • :

    #include <pempek_assert.h> 
    
    int main() 
    { 
        float min = 0.0f; 
        float max = 1.0f; 
        float v = 2.0f; 
        PEMPEK_ASSERT(v > min && v < max, 
           "invalid value: %f, must be between %f and %f", v, min, max); 
    
        return 0; 
    } 
    

    साथ संकेत देगा (I) gnore: वर्तमान दावे को अनदेखा करें

  • अनदेखा करें (एफ) अयस्क: फ़ाइल और लाइन जहां दावे निकाल दिया और कार्यक्रम के शेष निष्पादन के लिए इसे अनदेखा याद
  • पर ध्यान न दें (ए) डालूँगा: सभी शेष दावे (सभी फाइलों और लाइनों)
  • (डी) ebug उपेक्षा: में तोड़ फोन abort() तुरंत

आप इसके बारे में और अधिक जानकारी प्राप्त कर सकते हैं::

डिबगर अगर संलग्न, अन्यथा abort()
  • एक (ख) ort (विंडोज, पर सिस्टम उपयोगकर्ता एक डिबगर संलग्न करने के लिए संकेत देगा)

    आशा है कि मदद करता है।

  • +0

    धन्यवाद, यह बहुत साफ है। मैं अब अपने स्वयं के समाधान के साथ रहूंगा, हालांकि मैं कहूंगा, यह आपके यहां की तुलना में बदसूरत हैक जैसा दिखता है। –

    +0

    यदि आप कभी भी स्विच करने का निर्णय लेते हैं तो मुझे पिंग करने के लिए स्वतंत्र महसूस करें। मैंने मैक, लिनक्स, विंडोज़, आईओएस और एंड्रॉइड पर अब तक इसका परीक्षण किया। –

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