C Language
एक्स-मैक्रो
खोज…
परिचय
X-macros दोहराव वाले कोड को कम करने और डेटा / कोड पत्राचार को बनाए रखने के लिए एक पूर्वप्रक्रमक-आधारित तकनीक है। डेटा के एक सामान्य सेट पर आधारित कई अलग-अलग मैक्रो विस्तार एक एकल मास्टर मैक्रो के माध्यम से विस्तार के पूरे समूह का प्रतिनिधित्व करने के द्वारा समर्थित हैं, उस मैक्रो के प्रतिस्थापन पाठ में आंतरिक मैक्रो के विस्तार के एक अनुक्रम से मिलकर प्रत्येक डेटम शामिल है। आंतरिक मैक्रो को पारंपरिक रूप से X()
नाम दिया गया है, इसलिए तकनीक का नाम।
टिप्पणियों
एक्स-मैक्रो-स्टाइल मास्टर मैक्रो के उपयोगकर्ता को आंतरिक X()
मैक्रो के लिए अपनी परिभाषा प्रदान करने की उम्मीद है, और मास्टर मैक्रो का विस्तार करने के लिए इसके दायरे में है। मास्टर के आंतरिक मैक्रो संदर्भ इस प्रकार X()
की उपयोगकर्ता की परिभाषा के अनुसार विस्तारित होते हैं। इस तरह, स्रोत फ़ाइल में दोहराए जाने वाले बॉयलरप्लेट कोड की मात्रा कम की जा सकती है (केवल एक बार दिखाई दे रही है, X()
) के प्रतिस्थापन पाठ में, जैसा कि "अपने आप को दोहराएं नहीं" (DRY) दर्शन के अनुयायियों द्वारा इष्ट है।
इसके अतिरिक्त, X()
को फिर से परिभाषित करके X()
या एक से अधिक अतिरिक्त बार मास्टर मैक्रो का विस्तार करते हुए, एक्स मैक्रोस संबंधित डेटा और कोड को बनाए रखने की सुविधा प्रदान कर सकता है - मैक्रो का एक विस्तार डेटा की घोषणा करता है (उदाहरण के लिए एलीम तत्व या एनम सदस्य), और अन्य विस्तार संबंधित कोड का उत्पादन करते हैं।
यद्यपि "एक्स-मैक्रो" नाम आंतरिक मैक्रो के पारंपरिक नाम से आता है, तकनीक उस विशेष नाम पर निर्भर नहीं करती है। किसी भी मान्य मैक्रो नाम का उपयोग इसके स्थान पर किया जा सकता है।
आलोचनाओं में शामिल हैं
- स्रोत फ़ाइलें जो एक्स मैक्रोज़ पर भरोसा करती हैं, उन्हें पढ़ना अधिक कठिन है;
- सभी मैक्रोज़ की तरह, एक्स मैक्रोज़ सख्ती से पाठीय हैं - वे स्वाभाविक रूप से किसी भी प्रकार की सुरक्षा प्रदान नहीं करते हैं; तथा
- X मैक्रो कोड पीढ़ी के लिए प्रदान करते हैं। कॉलिंग फ़ंक्शन के आधार पर विकल्पों की तुलना में, एक्स मैक्रोज़ प्रभावी रूप से कोड को बड़ा बनाते हैं।
डॉ। डॉब्स ( http://www.drdobbs.com/the-new-cx-macros/184401387) में रैंडी मेयर्स के लेख [एक्स-मैक्रोज़] में एक्स मैक्रोज़ की एक अच्छी व्याख्या पाई जा सकती है।
Printfs के लिए X-macros का तुच्छ उपयोग
/* define a list of preprocessor tokens on which to call X */
#define X_123 X(1) X(2) X(3)
/* define X to use */
#define X(val) printf("X(%d) made this print\n", val);
X_123
#undef X
/* good practice to undef X to facilitate reuse later on */
यह उदाहरण निम्नलिखित कोड उत्पन्न करने वाले प्रीप्रोसेसर में परिणाम देगा:
printf("X(%d) made this print\n", 1);
printf("X(%d) made this print\n", 2);
printf("X(%d) made this print\n", 3);
Enum मान और पहचानकर्ता
/* declare items of the enum */
#define FOREACH \
X(item1) \
X(item2) \
X(item3) \
/* end of list */
/* define the enum values */
#define X(id) MyEnum_ ## id,
enum MyEnum { FOREACH };
#undef X
/* convert an enum value to its identifier */
const char * enum2string(int enumValue)
{
const char* stringValue = NULL;
#define X(id) if (enumValue == MyEnum_ ## id) stringValue = #id;
FOREACH
#undef X
return stringValue;
}
आगे आप अपने कोड में एन्यूमरेटेड वैल्यू का उपयोग कर सकते हैं और आसानी से इसके पहचानकर्ता को प्रिंट कर सकते हैं:
printf("%s\n", enum2string(MyEnum_item2));
विस्तार: एक्स मैक्रो को एक तर्क के रूप में दें
X-मैक्रो के दृष्टिकोण को "X" मैक्रो को मास्टर मैक्रो का तर्क बनाकर थोड़ा सामान्यीकृत किया जा सकता है। यह मैक्रो नाम टकराव से बचने में मदद करने और "एक्स" मैक्रो के रूप में एक सामान्य-उद्देश्य मैक्रो के उपयोग की अनुमति देने के फायदे हैं।
हमेशा एक्स मैक्रोज़ के साथ, मास्टर मैक्रो उन वस्तुओं की एक सूची का प्रतिनिधित्व करता है, जिनका महत्व उस मैक्रो के लिए विशिष्ट है। इस भिन्नता में, ऐसे मैक्रो को इस तरह परिभाषित किया जा सकता है:
/* declare list of items */
#define ITEM_LIST(X) \
X(item1) \
X(item2) \
X(item3) \
/* end of list */
एक तो आइटम नामों को मुद्रित करने के लिए कोड उत्पन्न कर सकता है जैसे:
/* define macro to apply */
#define PRINTSTRING(value) printf( #value "\n");
/* apply macro to the list of items */
ITEM_LIST(PRINTSTRING)
वह इस कोड में फैलता है:
printf( "item1" "\n"); printf( "item2" "\n"); printf( "item3" "\n");
मानक एक्स मैक्रोज़ के विपरीत, जहां "एक्स" नाम मास्टर मैक्रो की एक अंतर्निहित विशेषता है, इस शैली के साथ यह अनावश्यक या यहां तक कि अवांछनीय के लिए अवांछनीय हो सकता है मैक्रो का उपयोग तर्क के रूप में किया जाता है (इस उदाहरण में PRINTSTRING
)।
कोड जनरेशन
X- मैक्रोज़ का उपयोग कोड पीढ़ी के लिए किया जा सकता है, दोहराए जाने वाले कोड लिखकर: कुछ कार्यों को करने के लिए सूची पर पुनरावृति, या स्थिरांक, वस्तुओं या कार्यों का एक सेट घोषित करने के लिए।
यहां हम X-macros का उपयोग एक एनम को घोषित करने के लिए करते हैं जिसमें 4 कमांड होते हैं और उनके नाम के एक तार के रूप में
फिर हम एनम के स्ट्रिंग मानों को प्रिंट कर सकते हैं।
/* All our commands */
#define COMMANDS(OP) OP(Open) OP(Close) OP(Save) OP(Quit)
/* generate the enum Commands: {cmdOpen, cmdClose, cmdSave, cmdQuit, }; */
#define ENUM_NAME(name) cmd##name,
enum Commands {
COMMANDS(ENUM_NAME)
};
#undef ENUM_NAME
/* generate the string table */
#define COMMAND_OP(name) #name,
const char* const commandNames[] = {
COMMANDS(COMMAND_OP)
};
#undef COMMAND_OP
/* the following prints "Quit\n": */
printf("%s\n", commandNames[cmdQuit]());
इसी तरह, हम एनम वैल्यू द्वारा फंक्शन्स को कॉल करने के लिए जंप टेबल बना सकते हैं।
इसके लिए सभी कार्यों के लिए एक ही हस्ताक्षर की आवश्यकता होती है। यदि वे कोई तर्क नहीं लेते हैं और कोई इंटर्न लौटते हैं, तो हम इसे हेडर में इनम परिभाषा के साथ डालेंगे:
/* declare all functions as extern */
#define EXTERN_FUNC(name) extern int doCmd##name(void);
COMMANDS(EXTERN_FUNC)
#undef EXTERN_FUNC
/* declare the function pointer type and the jump table */
typedef int (*CommandFunc)(void);
extern CommandFunc commandJumpTable[];
निम्नलिखित सभी अलग-अलग संकलन इकाइयों में हो सकते हैं, जो ऊपर दिए गए भाग को हेडर के रूप में शामिल करते हैं:
/* generate the jump table */
#define FUNC_NAME(name) doCmd##name,
CommandFunc commandJumpTable[] = {
COMMANDS(FUNC_NAME)
};
#undef FUNC_NAME
/* call the save command like this: */
int result = commandJumpTable[cmdSave]();
/* somewhere else, we need the implementations of the commands */
int doCmdOpen(void) {/* code performing open command */}
int doCmdClose(void) {/* code performing close command */}
int doCmdSave(void) {/* code performing save command */}
int doCmdQuit(void) {/* code performing quit command */}
इस तकनीक का एक उदाहरण वास्तविक कोड में उपयोग किया जा रहा है जो क्रोमियम में GPU कमांड भेजने के लिए है ।