2013-02-13 52 views
7

मैं ओपनसोर्स प्रोजेक्ट टिग से कोड नमूना का जिक्र कर रहा हूं। एक महान उपकरण कौन सा है!मैक्रोज़ के माध्यम से एनम/स्ट्रक्चर को परिभाषित करने की क्या आवश्यकता है?

फ़ाइल: tig.c

मैं इस प्रकार अनुरोध गणन को परिभाषित करने के लिए एक कारण खोजने के लिए संघर्ष कर रहा हूँ: ..

enum request { 
#define REQ_GROUP(help) 
#define REQ_(req, help) REQ_##req 

     /* Offset all requests to avoid conflicts with ncurses getch values. */ 
     REQ_UNKNOWN = KEY_MAX + 1, 
     REQ_OFFSET, 
     REQ_INFO, 

     /* Internal requests. */ 
     REQ_JUMP_COMMIT, 

#undef REQ_GROUP 
#undef REQ_ 
}; 

भी संरचनाओं के रूप में अच्छी तरह से

static const struct request_info req_info[] = { 
#define REQ_GROUP(help) { 0, NULL, 0, (help) }, 
#define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) } 
     REQ_INFO 
#undef REQ_GROUP 
#undef REQ_ 
}; 

जैसा कि देखा जा सकता है REQ_GROUP # भ्रम पैदा करने के कई बार परिभाषित किया गया है .. कम से कम मेरे लिए। खैर मुझे पता है कि ऐसा करने का एक अच्छा कारण हो सकता है .. मैक्रोज़ का उपयोग कर कोड में enum/struct परिभाषा को छिपाने का वास्तविक कारण क्या है?

+2

क्या हो रहा है यह समझने के लिए मुझे अक्सर जीसीसी विकल्प '-dNI -E' के साथ एक स्रोत संकलित करना उपयोगी लगता है जिसके परिणामस्वरूप प्रीप्रोसेस्ड स्रोत होता है, लेकिन मैक्रोज़ परिभाषित किए बिना मैक्रो परिभाषाओं को दिखाता है, '# शामिल' कथन बरकरार है। –

+1

नीचे दिए गए उत्तरों में यह है।इस रणनीति के लिए एक सामान्य नाम "एक्स मैक्रो" है, विकिपीडिया इसके बारे में एक पृष्ठ है: http://en.wikipedia.org/wiki/X_Macro के रूप में करता है डॉ Dobbs: http://www.drdobbs.com/cpp/the -x-मैक्रो/228700289 – Vicky

+0

@Vicky drdobbs लिंक एक रत्न था! धन्यवाद! – ashishsony

उत्तर

7

यह आमतौर पर तब होता है जब एक ही डेटा स्रोत पर विभिन्न उपचारों का उपयोग किया जाना चाहिए।

उदाहरण के लिए, आप कर सकते हैं:

#define MY_LIST X(Elem1) X(Elem2) X(Elem3) 

और फिर:

enum MyEnum { 
# define X(e) e, 

    MY_LIST 

    Last 

# undef X 
}; 

जो मामले में, MY_LISTX की वर्तमान परिभाषा का उपयोग का विस्तार किया गया है।

अब, एक ही फाइल में, मैं भी MY_LIST का प्रयोग कर एक to_string विधि

char const* to_string(MyEnum e) { 
    switch(e) { 
#  define X(e) case e: return #e; 

     MY_LIST 

     case Last: return "Last"; 

#  undef X 
    } 
    return 0; 
} // to_string 

इस तरह, enum के मूल्यों का वह समूह ही कभी एक बार लिखा है दोनों enum बनाने के लिए, और स्वचालित रूप से कर सकते हैं और इसके साथ निपटने के कई तरीके इस सेट के साथ सिंक में रखा जाता है।

1

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

उन मैक्रोज़ के बिना, गणना और डेटा संरचना को अलग-अलग बनाए रखा जाना चाहिए, उन्हें एक दूसरे के साथ संगत रखने के लिए देखभाल करना, जिसमें अधिक काम और त्रुटि के लिए अधिक दायरा शामिल है।

#define REQ_INFO \ 
REQ_GROUP("View switching") \ 
VIEW_INFO(VIEW_REQ), \ 
\ 
REQ_GROUP("View manipulation") \ 
REQ_(ENTER, "Enter current line and scroll"), \ 
REQ_(NEXT, "Move to next"), \ 
REQ_(PREVIOUS, "Move to previous"), \ 
< output omitted as it is too long > 

तो, उदाहरण के लिए, संरचना आप से पता चला है में विस्तारित:

1

आप उसी फ़ाइल में महत्वपूर्ण परिभाषित करता है चूक गए

static const struct request_info req_info[] = { 
    { 0, NULL, 0, "View switching" }, 
    < VIEW_INFO also expands to some long structure that was ommited here > 
    { 0, NULL, 0, "View manipulation" }, 
    { REQ_ENTER, ENTER, STRING_SIZE("ENTER"), "Enter current line and scroll"}, 
    { REQ_NEXT, NEXT, STRING_SIZE("NEXT"), "Move to next"} 
    < and so on > 
}; 

अन्य उत्तर उल्लेख किया है, यह ज्यादातर किया जाता है एकाधिक संरचनाओं/एन्युमरेटर्स को सिंक्रनाइज़ करने के लिए।