2013-06-19 2 views
13

मैं एक पैटर्न मूल रूप से है कि मध्यमक्या सी मैक्रो के लिए एक तर्क के रूप में कोड ब्लॉक का उपयोग करना ठीक है?

if(condition){ 
    struct Foo m = start_stuff(); 
    { m.foo = bar(1,2); m.baz = 17; } //this part varies 
    end_stuff(); 
} 

में बदलता है यह एक मैक्रो taht बनाने के लिए ठीक है एक हिस्सा के साथ कुछ बॉयलरप्लेट कोड है कि है एक तर्क के रूप कि मध्यवर्ती कोड ब्लॉक लेता है? सी में मैक्रो विस्तार के नियम बहुत जटिल लगते हैं, इसलिए मुझे यकीन नहीं है कि क्या कोई भी कोने के मामले नहीं हैं जो भविष्य में मुझे आ सकते हैं और मुझे काट सकते हैं (विशेष रूप से, मुझे नहीं पता कि मैक्रो तर्क अलग कैसे हैं यदि मेरा कोड इसमें अल्पविराम है)।

#define MY_MACRO(typ, do_stuff) do { \ 
    if(condition){ \ 
     struct typ m = start_stuff(); \ 
     do_stuff; \ 
     end_stuff(); \ 
    } \ 
}while(0) 

//usage 
MY_MACRO(Foo, { 
    m.foo = bar(1,2); 
    m.baz = 17; 
}); 

अब तक केवल बात यह है कि मैं के break और continue पर कब्जा कर लिया जा रहा है अगर मैं अपने मैक्रो में पाशन बयानों का उपयोग करें और है कि मेरे विशेष उपयोग के मामले के लिए एक स्वीकार्य दुविधा यह होगा लगता है में कामयाब रहे।

संपादित करें: बेशक, अगर मैं कर सकता तो मैं एक फ़ंक्शन का उपयोग करता। इस प्रश्न में मैंने जो उदाहरण इस्तेमाल किया है वह सरलीकृत है और बिट्स को प्रदर्शित नहीं करता है जो केवल मैक्रो जादू के साथ काम कर सकता है।

+5

डू-टाइम-झूठी एक मानक मुहावरे है जो आपको मैक्रो से बाहर निकलने में सक्षम बनाता है यदि आपको आवश्यकता हो। मैक्रोज़ के बारे में मेरा एकमात्र आरक्षण यह है कि यह विशेष रूप से दुर्घटना स्थितियों में डीबगिंग मुश्किल बनाता है। यदि लगभग 100 लाइनों का लंबा मैक्रो ब्लॉक है, और 5 घंटे तक चलने के बाद, मैक्रो में सैकड़ों कॉलों में से किसी एक पर कोड क्रैश हो जाता है, तो आपको इसे ट्रैक करने में कठिनाई होगी। – cup

+0

त्रुटियों को संकलित करने के लिए, क्लैंग का उपयोग करें। यह विशाल मैक्रोज़ के अंदर वाक्यविन्यास त्रुटियों की पहचान करता है। रन-टाइम त्रुटियों के लिए, मैं आमतौर पर 'gcc -E prog.c | grep -v^# | indent> prog-dbg.c' का उपयोग करता हूं और फिर अन्य कोड में' prog-dbg.c' संकलित और लिंक करता हूं। यह बेकार है लेकिन काम कर रहा है। – user172818

+1

आपकी अवधारणा ठीक है जैसा लगता है ... लेकिन आप अपने जीवन को आसान बनाने के लिए कॉल बैक फ़ंक्शंस क्यों नहीं करते हैं? क्या इनलाइन गति बहुत महत्वपूर्ण है? @cup पॉइंट्स के रूप में यह डीबग करने के लिए एक दर्द है। –

उत्तर

12

आप एक मैक्रो तर्क में कोड ब्लॉक डाल सकते हैं बशर्ते कि इसमें कोई अनचाहे कॉमा न हो। आपके उदाहरण में, तर्क में एकमात्र कॉमा संरक्षित है क्योंकि यह कोष्ठक से घिरा हुआ है।

ध्यान दें कि केवल ब्रांड्स कमांड कोष्ठक देता है। ब्रैकेट्स ([]) और ब्रेसिज़ ({}) नहीं।

+0

यह वास्तव में मुझे यह जानने में मदद मिली कि मुझे त्रुटि क्यों मिली: 'त्रुटि: मैक्रो "some_macro_name" 8 तर्क पारित किया, लेकिन केवल 7' – xhg

+0

लेता है जाहिर है जो भी आप इन्हें कहते हैं:' <> '(कोण ब्रैकेट्स?) या तो नहीं। इसे एक से अधिक टेम्पलेट तर्क – Sean

+0

@sean के साथ कोड का उपयोग करने का प्रयास करने में मिला: हाँ, केवल ब्रांड्स का मतलब केवल कोष्ठक है। – rici

1

आप कोड ब्लॉक को मैक्रो में डाल सकते हैं लेकिन आपको चेतावनी दी जानी चाहिए कि यह डीबगर का उपयोग करके बहुत कठिन बना देता है। आईएमएचओ सिर्फ एक समारोह लिखने या कोड की लाइनों को कास्ट करने के लिए बेहतर है।

0

इसके बजाय फ़ंक्शन पॉइंटर्स के बारे में (और वैकल्पिक रूप से inline फ़ंक्शंस) के बारे में कैसे?

void do_stuff_inner_alpha(struct Foo *m) 
{ 
    m->foo = bar(1,2); m->baz = 17; 
} 

void do_stuff_inner_beta(struct Foo *m) 
{ 
    m->foo = bar(9, 13); m->baz = 445; 
} 


typedef void(*specific_modifier_t)(struct Foo *); 

void do_stuff(specific_modifier_t func) 
{ 
    if (condition){ 
     struct Foo m = start_stuff(); 
     func(&m); //this part varies 
     end_stuff(); 
    } 
} 

int main(int argc, const char *argv[]) 
{ 
    do_stuff(do_stuff_inner_beta); 

    return EXIT_SUCCESS; 
} 
+0

दुर्भाग्य से, मेरे रिला कोड में structs के प्रकार भिन्न होते हैं और मैक्रो के लिए एक अतिरिक्त तर्क हैं।हालांकि इसे शून्य पॉइंटर्स के साथ काम किया जा सकता है, वहीं अन्य चीजें भी हैं जो तकनीकी कारणों से मैक्रोज़ के साथ ही कर सकती हैं। – hugomg

+0

एक आवश्यक अमूर्त परत क्या हो सकता है समायोजित करने के लिए इसके बजाय अधिक हस्ताक्षरकर्ता डिज़ाइन परिवर्तनों पर विचार करें। –

+0

दुर्भाग्यवश, मैं वास्तव में [एनईएससी] (https://en.wikipedia.org/wiki/NesC) के साथ काम कर रहा हूं, एक सी बोलीभाषा और कुछ चीजों को मुझे पैरामीट्रिज करने की आवश्यकता है इंटरफ़ेस हैं और नामों के नाम टाइप करें जो ' सामान्य कार्य निष्कर्षण के लिए खुद को अच्छी तरह से उधार देना। – hugomg

-2

अपने सवाल का जवाब देने से पहले मैं जानना चाहते हैं क्यों आप मैक्रो के लिए कोड का कि ब्लॉक परिवर्तित करना चाहते हैं "यह मैक्रो का उपयोग करने के लिए ठीक है।" क्या आप हासिल करने की कोशिश कर रहे हैं और किस कीमत पर?

यदि कोड का एक ही ब्लॉक बार-बार उपयोग कर रहा है, तो इसे एक फ़ंक्शन में परिवर्तित करना बेहतर होगा, शायद एक इनलाइन फ़ंक्शन और इसे इनलाइन बनाने के लिए कंपाइलर पर छोड़ दें।

क्या आपको क्रैश \ समस्या में भाग लेना चाहिए, मैक्रो को डीबग करना एक कठिन काम है।

0

"क्या यह ठीक है?" इसका मतलब हो सकता है:

  1. क्या यह काम करेगा? यहां जवाब आम तौर पर हां है, लेकिन नुकसान हैं। एक, as rici mentioned, एक अनजान कॉमा है। असल में, याद रखें कि मैक्रो विस्तार एक प्रति & पेस्ट ऑपरेशन है, और प्रीप्रोसेसर उस कोड को समझता नहीं है जो प्रतिलिपि बनाता है और पेस्ट करता है।

  2. क्या यह एक अच्छा विचार है? मैं कहूंगा कि जवाब आमतौर पर नहीं है। यह आपके कोड को पढ़ने के लिए अपठनीय और कठिन बनाता है। कुछ दुर्लभ मामलों में, यह लागू होने पर विकल्प से बेहतर हो सकता है, लेकिन यह अपवाद है।

3

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

#define CAT(prefix, suffix)   prefix ## suffix 
#define _UNIQUE_LABEL(prefix, suffix) CAT(prefix, suffix) 
#define UNIQUE_LABEL(prefix)   _UNIQUE_LABEL(prefix, __LINE__) 

#define MY_MACRO(typ, condition) if (condition) { \ 
            struct typ m = start_stuff(); goto UNIQUE_LABEL(enter);} \ 
            if (condition) while(1) if (1) {end_stuff(); break;} \ 
                  else UNIQUE_LABEL(enter): 

नोट यह है कि:

//usage 
MY_MACRO(Foo, condition) { 
    m.foo = bar(1,2); 
    m.baz = 17; 
} 

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

इसके अलावा

, आप एक नया ब्लॉक गुंजाइश किसी एक मैक्रो का उपयोग करने के 'm' चर के साथ प्रदूषण अपने दायरे से बचने के लिए चाहते हो सकता है: का उपयोग कर 'ब्रेक' में एक नेस्टेड लूप के अंदर नहीं,

{MY_MACRO(Foo, condition) { 
    m.foo = bar(1,2); 
    m.baz = 17; 
}} 
बेशक

यौगिक बयान 'end_stuff()' को छोड़ देगा। आसपास के पाश को तोड़ने के लिए ') end_stuff (' उन लोगों के लिए अनुमति देने के लिए और अभी भी कहते हैं, मुझे लगता है कि आप एक शुरुआत टोकन और के रूप में समाप्त टोकन के माध्यम से परिसर बयान संलग्न करना होगा:

#define MY_MACRO_START(typ, condition) if (condition) { \ 
              struct typ m = start_stuff(); do { 

#define MY_MACRO_EXIT     goto UNIQUE_LABEL(done);} while (0); \ 
             end_stuff(); break; \ 
             UNIQUE_LABEL(done): end_stuff();} 

MY_MACRO_START(foo, condition) { 
    m.foo = bar(1,2); 
    m.baz = 17; 
} MY_MACRO_END 

ध्यान दें कि क्योंकि उस दृष्टिकोण में 'ब्रेक' का, MY_MACRO_EXIT मैक्रो केवल लूप या स्विच के अंदर प्रयोग योग्य होगा। आप जब एक पाश के अंदर नहीं एक सरल कार्यान्वयन इस्तेमाल कर सकते हैं:

#define MY_MACRO_EXIT_NOLOOP } while (0); end_stuff();} 

मैं एक मैक्रो तर्क के रूप में 'शर्त' का इस्तेमाल किया है, लेकिन आप भी मैक्रो में सीधे एम्बेड अगर वांछित कर सकते हैं।

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