दिलचस्प पोस्ट
एडीटी अपडेट के बाद ClassNotFound अपवाद फ़ॉर्म सबमिट होने के बाद रीडायरेक्ट रोकें MVC3 मान्यकरण – समूह से एक की आवश्यकता है शब्दकोश कुंजी में स्विचेस से ऐरे IIS7 न्यूनतम अनुमति अनुरोधों को देने में विफल रहा कुछ ऑपरेटरों को सदस्यों के रूप में लागू करने का तर्क जावा थ्रेड्स और ओएस थ्रेड्स के बीच भेद? आवेदन के अंदर बाह्य अनुप्रयोग टुकड़ा / गतिविधि का उपयोग करें अजगर के लिए auto.arima () समकक्ष दृश्य स्टूडियो में एएसएम से सी मानक पुस्तकालय फ़ंक्शन कॉल करें कंसोल में प्रवेश के बिना कुंजी दबाएं देखें कि उपयोगकर्ता सी # + एस्प.net में सक्रिय निर्देशिका समूह का हिस्सा है या नहीं मेमोरी फ्रेग्मेंटेशन को कैसे हल करें I मैं किसी निश्चित तिथि के सप्ताह की संख्या कैसे निर्धारित कर सकता हूं? एंड्रॉइड: परिवर्तन बटन पाठ और पृष्ठभूमि का रंग

मैक्रोज़ में जाहिरा तौर पर अर्थहीन करते-करते और if-else बयान क्यों का उपयोग करें?

कई सी / सी + मैक्रोज़ में मैं मैक्रो का कोड देख रहा हूं जो लूप में दिखता है, do while लगता है जैसे लूप do while कोई अर्थ do while होता। ये उदाहरण हैं

 #define FOO(X) do { f(X); g(X); } while (0) #define FOO(X) if (1) { f(X); g(X); } else 

मैं नहीं देख do while कर रहा है। क्यों न सिर्फ यह लिखिए?

 #define FOO(X) f(X); g(X) 

Solutions Collecting From Web of "मैक्रोज़ में जाहिरा तौर पर अर्थहीन करते-करते और if-else बयान क्यों का उपयोग करें?"

do ... while और if ... else इसे बनाने के लिए वहां मौजूद हैं, ताकि आपके मैक्रो के बाद एक अर्धविराम हमेशा एक ही बात का मतलब हो। मान लें कि आपके पास दूसरा मैक्रो जैसी कुछ था।

 #define BAR(X) f(x); g(x) 

अब अगर आप BAR(X); का प्रयोग कर रहे थे BAR(X); if ... else एक if ... else बयान में, जहां बयान के बॉलीवुड को घुंघराले ब्रैकेट में लपेट नहीं किया गया था, तो आपको एक बुरा आश्चर्य मिलेगा

 if (corge) BAR(corge); else gralt(); 

उपरोक्त कोड में विस्तार होगा

 if (corge) f(corge); g(corge); else gralt(); 

जो वाक्यविन्यास रूप से ग़लत है, क्योंकि अन्य अब अगर से जुड़ा नहीं है। यह मैक्रो के अंदर घुंघराले ब्रेसिज़ में चीजों को लपेटने में मदद नहीं करता है, क्योंकि ब्रेसिज़ के अर्धविराम वाक्यविन्यास रूप से गलत है

 if (corge) {f(corge); g(corge);}; else gralt(); 

समस्या को ठीक करने के दो तरीके हैं। पहली बार एक अल्पविराम का उपयोग मैक्रो के भीतर क्रम के बयान के बिना करने के लिए अभिव्यक्ति की तरह कार्य करने की अपनी क्षमता को लूटने के लिए करना है

 #define BAR(X) f(X), g(X) 

बार BAR उपरोक्त संस्करण में उपरोक्त कोड को आगे बढ़ाता है, जो वाक्यविन्यास सही है।

 if (corge) f(corge), g(corge); else gralt(); 

यह कार्य नहीं करता है अगर f(X) बजाय आपके पास एक जटिल कोड है जो अपने ब्लॉक में जाने की जरूरत है, उदाहरण के लिए स्थानीय चर घोषित करने के लिए कहें सबसे सामान्य मामले में समाधान कुछ do ... while मैक्रो एक एकल कथन के कारण होने के कारण होता है जो बिना भ्रम के एक अर्धविराम लेता है

 #define BAR(X) do { \ int i = f(X); \ if (i > 4) g(i); \ } while (0) 

आप का उपयोग करने के लिए do ... while , आप कुछ के साथ खाना बना सकते हैं if ... else भी, हालांकि जब if ... else अंदर फैलता है if ... else यह एक " झूलने वाला होता है ", जो कि वर्तमान कोड के रूप में एक मौजूदा लंघन और समस्या को खोजने के लिए कठिन भी हो सकता है

 if (corge) if (1) { f(corge); g(corge); } else; else gralt(); 

बिंदु उन संदर्भों में सेमीकोलन का उपयोग करना है जहां एक लटकती अर्धविराम गलत है बेशक, इस बिंदु पर (और संभवत: शायद) तर्क दिया जा सकता है कि BAR को एक वास्तविक समारोह के रूप में घोषित करना बेहतर होगा, मैक्रो नहीं।

संक्षेप में, do ... while सी प्रीप्रोसेसर की कमियों के आसपास काम करना है जब उन सी स्टाइल गाइड आपको सी प्रीप्रोसेसर को बंद करने के लिए कहते हैं, तो यह ऐसी चीज है जिसे वे चिंतित हैं

मैक्रोज़ टेक्स्ट के टुकड़े कॉपी / चिपकाए जाते हैं प्री-प्रोसेसर को वास्तविक कोड में डाल दिया जाता है; मैक्रो के लेखक उम्मीद करते हैं कि प्रतिस्थापन मान्य कोड का उत्पादन करेगा

उसमें सफल होने के लिए तीन अच्छे "टिप्स" हैं:

मैक्रो वास्तविक कोड की तरह व्यवहार करें

सामान्य कोड आमतौर पर एक अर्ध-बृहदान्त्र द्वारा समाप्त होता है क्या उपयोगकर्ता व्यू कोड को एक की जरूरत नहीं है …

 doSomething(1) ; DO_SOMETHING_ELSE(2) // <== Hey? What's this? doSomethingElseAgain(3) ; 

इसका अर्थ है कि उपयोगकर्ता को संकलक को उम्मीद है कि अर्ध-बृहद अनुपस्थित है।

लेकिन वास्तविक असली अच्छा कारण यह है कि कुछ समय में, मैक्रो के लेखक को एक वास्तविक कार्य (शायद इनलाइन) के साथ मैक्रो को बदलने की आवश्यकता होगी। तो मैक्रो वास्तव में एक जैसा व्यवहार करना चाहिए

तो हमारे पास अर्ध-बृहदान्त्र की आवश्यकता होती है।

एक मान्य कोड बनाएं

जैसा कि jfm3 के उत्तर में दिखाया गया है, कभी-कभी मैक्रो में एक से अधिक अनुदेश होते हैं और यदि मैक्रो का उपयोग अगर एक बयान के अंदर किया जाता है, तो यह समस्याग्रस्त होगा:

 if(bIsOk) MY_MACRO(42) ; 

इस मैक्रो को विस्तारित किया जा सकता है:

 #define MY_MACRO(x) f(x) ; g(x) if(bIsOk) f(42) ; g(42) ; // was MY_MACRO(42) ; 

bIsOk के मूल्य की परवाह किए बिना g फंक्शन निष्पादित किया जाएगा।

इसका मतलब है कि हमें मैक्रो को एक अवसर जोड़ना होगा:

 #define MY_MACRO(x) { f(x) ; g(x) ; } if(bIsOk) { f(42) ; g(42) ; } ; // was MY_MACRO(42) ; 

एक मान्य कोड 2 बनाएं

अगर मैक्रो कुछ ऐसा है:

 #define MY_MACRO(x) int i = x + 1 ; f(i) ; 

हमें निम्न कोड में एक और समस्या हो सकती है:

 void doSomething() { int i = 25 ; MY_MACRO(32) ; } 

क्योंकि यह विस्तार होगा:

 void doSomething() { int i = 25 ; int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ; } 

यह कोड संकलन नहीं करेगा, ज़ाहिर है। तो, फिर, समाधान एक क्षेत्र का उपयोग कर रहा है:

 #define MY_MACRO(x) { int i = x + 1 ; f(i) ; } void doSomething() { int i = 25 ; { int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ; } 

कोड ठीक से फिर से बर्ताव करता है।

अर्द्ध-बृहदान्त्र का + संयोजन प्रभाव?

एक सी / सी + मुहावरा है जो इस आशय का उत्पादन करता है: कर / जब लूप:

 do { // code } while(false) ; 

ऐसा करते / करते समय एक गुंजाइश बना सकते हैं, इस प्रकार मैक्रो के कोड को निकलते हैं, और अंत में एक अर्द्ध-बृहदान्त्र की आवश्यकता होती है, इस प्रकार एक को जरूरत पड़ने पर कोड में विस्तार होता है

बोनस?

सी ++ कंपाइलर डू / लूप को ऑप्टिमाइज़ करेगा, क्योंकि इसकी पोस्ट-अटिल झूठी है, समय के संकलन में ज्ञात है। इसका अर्थ है कि मैक्रो की तरह:

 #define MY_MACRO(x) \ do \ { \ const int i = x + 1 ; \ f(i) ; g(i) ; \ } \ while(false) void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) MY_MACRO(42) ; // Etc. } 

सही ढंग से विस्तार होगा

 void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) do { const int i = 42 + 1 ; // was MY_MACRO(42) ; f(i) ; g(i) ; } while(false) ; // Etc. } 

और फिर संकलित और अनुकूलित किया जाता है

 void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) { f(43) ; g(43) ; } // Etc. } 

@ jfm3 – आपके पास सवाल का अच्छा जवाब है। आप यह भी जोड़ सकते हैं कि मैक्रो मुहावरों को संभवतः अधिक खतरनाक (क्योंकि कोई त्रुटि नहीं है) सरल 'if' कथन के साथ अनपेक्षित व्यवहार को रोकता है:

 #define FOO(x) f(x); g(x) if (test) FOO( baz); 

फैलता है:

 if (test) f(baz); g(baz); 

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

उपर्युक्त उत्तर इन संरचनाओं के अर्थ को समझाते हैं, लेकिन उन दोनों के बीच एक महत्वपूर्ण अंतर है जो उल्लेख नहीं किया गया था। वास्तव में, ऐसा करने का एक कारण do ... while if ... else निर्माण करना है

if ... else निर्माण की समस्या यह है कि यह आपको सेमीकोलन डाल करने के लिए बाध्य नहीं करता है इस कोड की तरह:

 FOO(1) printf("abc"); 

हालांकि हमने अर्धविराम (गलती से) छोड़ दिया, हालांकि कोड में विस्तार होगा

 if (1) { f(X); g(X); } else printf("abc"); 

और चुपचाप संकलित होगा (हालांकि कुछ कंपाइलर्स अप्राप्य कोड के लिए एक चेतावनी जारी कर सकते हैं) लेकिन printf कथन कभी भी निष्पादित नहीं किया जाएगा।

do ... while निर्माण में ऐसी कोई समस्या नहीं है, क्योंकि केवल while(0) अर्धविराम के बाद एकमात्र मान्य टोकन है

यद्यपि यह उम्मीद की जाती है कि कंपलर do { ... } while(false); अनुकूलन do { ... } while(false); loops, वहाँ एक और समाधान है जो कि निर्माण की आवश्यकता नहीं होगी। समाधान अल्पविराम ऑपरेटर का उपयोग करना है:

 #define FOO(X) (f(X),g(X)) 

या इससे भी अधिक आश्चर्यजनक रूप से:

 #define FOO(X) g((f(X),(X))) 

हालांकि यह अलग-अलग निर्देशों के साथ अच्छी तरह से काम करेगा, यह उन मामलों के साथ काम नहीं करेगा जहां चर का निर्माण और #define भाग के रूप में उपयोग किया जाता है:

 #define FOO(X) (int s=5,f((X)+s),g((X)+s)) 

इस के साथ, निर्माण / निर्माण का उपयोग करने के लिए मजबूर हो जाएगा।

जेन्स गुस्टेड की पी 99 प्रीप्रोसेसर लाइब्रेरी (हां, यह सच है कि ऐसी कोई बात भी मेरे दिमाग को भी उड़ा रही है!) if(1) { ... } else निम्न को परिभाषित करके एक छोटे लेकिन महत्वपूर्ण तरीके से निर्माण करता है:

 #define P99_NOP ((void)0) #define P99_PREFER(...) if (1) { __VA_ARGS__ } else #define P99_BLOCK(...) P99_PREFER(__VA_ARGS__) P99_NOP 

इसके लिए तर्क यह है कि, do { ... } while(0) विपरीत, do { ... } while(0) निर्माण, break और continue अभी भी ब्लॉक के अंदर काम करता है, लेकिन ((void)0) एक वाक्य रचना त्रुटि बनाता है यदि सेमीकोलन के बाद छोड़ा जाता है मैक्रो कॉल, जो अन्यथा अगले ब्लॉक को छोड़ देगा। (वास्तव में यहां एक "झूठी समस्या" समस्या नहीं है, क्योंकि इससे निकटतम तक बन्द हो जाता है, जो मैक्रो में एक है।)

यदि आप चीजों के प्रकार में रुचि रखते हैं जो सी प्रीप्रोसेसर के साथ अधिक या कम सुरक्षित रूप से किया जा सकता है, तो उस पुस्तकालय को देखें

कुछ कारणों से मैं पहले जवाब पर टिप्पणी नहीं कर सकता …

आप में से कुछ स्थानीय चर के साथ मैक्रोज़ दिखा चुके हैं, लेकिन कोई भी उल्लेख नहीं करता कि आप मैक्रो में किसी भी नाम का उपयोग नहीं कर सकते हैं! यह उपयोगकर्ता को कुछ दिन काट देगा! क्यूं कर? क्योंकि इनपुट तर्क आपके मैक्रो टेम्पलेट में प्रतिस्थापित किए गए हैं। और आपके मैक्रो उदाहरणों में आपने संभवतः सबसे अधिक इस्तेमाल किए गए वैरिएबल नाम का उपयोग किया है I

उदाहरण के लिए, जब निम्न मैक्रो

 #define FOO(X) do { int i; for (i = 0; i < (X); ++i) do_something(i); } while (0) 

निम्न फ़ंक्शन में उपयोग किया जाता है

 void some_func(void) { int i; for (i = 0; i < 10; ++i) FOO(i); } 

मैक्रो इच्छित चर I का उपयोग नहीं करेगा, जो some_func की शुरुआत में घोषित किया गया है, लेकिन स्थानीय चर, जो कि घोषित किया गया है … जबकि मैक्रो का लूप

इस प्रकार, मैक्रो में आम चर नामों का कभी इस्तेमाल न करें!

मुझे नहीं लगता कि इसका उल्लेख किया गया है इसलिए इस पर विचार करें

 while(i<100) FOO(i++); 

में अनुवाद किया जाएगा

 while(i<100) do { f(i++); g(i++); } while (0) 

नोटिस कैसे मैक्रो द्वारा i++ का दो बार मूल्यांकन किया जाता है इससे कुछ रोचक त्रुटियां हो सकती हैं

do {} while (0) से बेहतर do {} while (0) और if (1) {} else , कोई भी बस ({}) उपयोग कर सकता है:

 #define FOO(X) ({f(X); g(X);}) 

और यह वाक्यविन्यास रिटर्न मानों के साथ संगत है ( do {} while (0) नहीं है do {} while (0) नहीं है), जैसा कि:

 return FOO("X"); 

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

 #define CALL_AND_RETURN(x) if ( x() == false) break; do { CALL_AND_RETURN(process_first); CALL_AND_RETURN(process_second); CALL_AND_RETURN(process_third); //(simply add other calls here) } while (0);