Table of Contents
सी में मैक्रोज़ प्रीप्रोसेसिंग चरण की एक शक्तिशाली विशेषता है जो प्रोग्रामर को स्थिरांक, इनलाइन कोड स्निपेट्स को परिभाषित करने और सशर्त संकलन करने की अनुमति देती है। जब प्रभावी ढंग से उपयोग किया जाता है, तो वे कोड पुन: प्रयोज्यता और रखरखाव क्षमता को काफी बढ़ाते हैं, जिससे डेवलपर्स को क्लीनर, अधिक लचीला कार्यक्रम लिखने में सक्षम बनाया जाता है। हालांकि, उनकी शक्ति जोखिमों के साथ आती है; अनुचित मैक्रो उपयोग सूक्ष्म बगों को पेश कर सकता है और कोड को डब करने के लिए कठिन बना सकता है। यह लेख पता चलता है कि कैसे उद्योग के अनुभव और सी मानक से तैयार सर्वोत्तम प्रथाओं के साथ, अधिकतम लाभ के लिए मैक्रोज़ का उपयोग करना है।
क्या है मैक्रो?
मैक्रोज़ को ] निर्देश का उपयोग करके परिभाषित किया गया है और संकलन शुरू होने से पहले C प्रीप्रोसेसर द्वारा संसाधित किया जाता है। प्रीप्रोसेसर सरल पाठ प्रतिस्थापन करता है: स्रोत कोड में मैक्रो नाम की हर घटना को मैक्रो की परिभाषा के साथ बदल दिया जाता है। यह प्रतिस्थापन पूरी तरह से पाठ्य है और इसका सम्मान नहीं है गुंजाइश या टाइप चेकिंग। मैक्रोज़ हो सकता है ] ओब्जेक्ट-like (निरंतरंतर के लिए इस्तेमाल किया गया) या ]]]]] ]]]]]]]]]]]] [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
#define PI 3.14159 // object-like macro
#define SQUARE(x) ((x)*(x)) // function-like macro
इस पूर्व प्रसंस्करण कदम को समझना महत्वपूर्ण है क्योंकि मैक्रोज़ कार्यों या चर के समान नियमों का पालन नहीं करते हैं। वे इनलाइन का विस्तार कर रहे हैं, जो उन्हें प्रदर्शन के फायदे देते हैं लेकिन यह भी अद्वितीय चुनौतियों का परिचय देते हैं।
कोड पुन: प्रयोज्यता और रखरखाव के लिए मैक्रोज़ के लाभ
जब विचारपूर्वक लागू किया जाता है, तो मैक्रो बड़े या प्रदर्शन-संवेदनशील कोडबेस में कई ठोस फायदे प्रदान करते हैं:
- Code Reusability: एक बार एक आम गणना या स्निपेट को परिभाषित करें और पूरे कार्यक्रम में इसका उपयोग करें। प्रत्येक उदाहरण को स्वचालित रूप से मैक्रो अपडेट बदल रहा है।
- ]]] मैजिक नंबर का उन्मूलन: या जैसे बिखरे हुए अक्षरों के बजाय, उन्हें सार्थक नाम देते हैं। यह पठनीयता में सुधार करता है और ट्यूनिंग पैरामीटर्स को त्रयी बनाता है।
- ]Performanceगेन: फंक्शन जैसी मैक्रोज़ किसी फंक्शन कॉल के ओवरहेड से बच जाती हैं। छोटे, अक्सर इस्तेमाल किए जाने वाले ऑपरेशनों के लिए (जैसे, मिनट / अधिकतम, वर्ग), मैक्रोज़ कुछ कम्पाइलर्स में भी इनलाइन फंक्शन की तुलना में तेज़ी से हो सकते हैं जहां इनलाइनिंग की गारंटी नहीं है।
- ]Conditional संकलन : मैक्रोज़ हाथ में हाथ से हाथ में काम करते हैं, , और ], संकलित समय की स्थिति के आधार पर कोड को शामिल करने या बाहर करने के लिए। यह मंच-विशिष्ट कोड, डिबग बिल्ड्स, या सुविधा टॉगल के लिए आवश्यक है।
- ]Simplified विन्यास : मैक्रो को एक ही हेडर में विभिन्न मूल्यों के साथ परिभाषित करके, आप कार्यान्वयन फ़ाइलों को छूने के बिना एक संपूर्ण कोडबेस के व्यवहार को अनुकूलित कर सकते हैं।
रोबस्ट मैक्रो लिखना: सर्वश्रेष्ठ अभ्यास
मैक्रोज़ की लचीलापन भी उनका खतरा है। एक खराब लिखित मैक्रो अप्रत्याशित व्यवहार का कारण बन सकता है जो ट्रेस करना मुश्किल है। अपने मैक्रोज़ को सुरक्षित और रखरखाव रखने के लिए इन सर्वोत्तम प्रथाओं का पालन करें।
हमेशा Parenthesize पैरामीटर्स और संपूर्ण अभिव्यक्ति
चूंकि मैक्रो टेक्स्ट प्रतिस्थापन हैं, ऑपरेटर की पूर्ववर्तीता उन्हें तोड़ सकती है। ]] की तरह एक मैक्रो का विस्तार (जो 11, 25 नहीं के बराबर है) होगा। यह तय हर पैरामीटर को पैरेंटेस में संलग्न करना और पूरी अभिव्यक्ति को लपेटना है:
#define SQUARE(x) ((x) * (x)) // now SQUARE(3+2) works correctly
तर्कों के एकाधिक मूल्यांकन से बचें
मैक्रो तर्क के रूप में बदल रहे हैं। यदि किसी तर्क के दुष्प्रभाव (जैसे, ) हैं, तो इसका मूल्यांकन एक से अधिक बार किया जा सकता है। उदाहरण के लिए:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
int x = 5;
int max = MAX(x++, 10); // expands to ((x++) > (10) ? (x++) : (10)) // x incremented twice!
इससे बचने के लिए, इनलाइन कार्यों को पसंद करते हैं या उपयोगकर्ताओं को चेतावनी देने के लिए सावधानीपूर्वक नामकरण सम्मेलनों का उपयोग करते हैं। यदि आपको मैक्रो का उपयोग करना चाहिए, तो उस तर्क में साइड इफेक्ट नहीं होना चाहिए।
मैक्रो नाम के लिए ऊपरी केस का उपयोग करें
सम्मेलन के बाद, मैक्रोज़ को ऊपरी केस अक्षरों (जैसे, [[FLT: 13]]]] में लिखा जाता है, [[FLT: 14]]])। इससे उन्हें चर और कार्यों से बाहर खड़े हो जाओ, जिससे आकस्मिक टकराव की संभावना कम हो जाती है।
मल्टी-स्टेटमेंट ब्लॉक के लिए Do-While के साथ अंत मैक्रोज़
जब एक मैक्रो को परिभाषित किया जाता है जिसमें कई कथन होते हैं, तो उन्हें एक लूप में लपेटो। यह मैक्रो को सभी संदर्भों (जैसे, ]] के बाद सही ढंग से व्यवहार करता है।
#define LOG_ERROR(msg) do { \
fprintf(stderr, "Error: %s\n", msg); \
exit(1); \
} while (0)
मैक्रोस को पूरी तरह से
मैक्रोज़ कार्यों की स्वयं-दस्ताने वाली प्रकृति की कमी नहीं है। हमेशा तर्कों, अपेक्षित व्यवहार और किसी भी सीमा को निर्धारित करने वाली टिप्पणियां जोड़ें। उपयुक्त होने पर डॉक्सिगेन-शैली टिप्पणियों का उपयोग करें।
उन्नत मैक्रो तकनीक
C Preprocessor शक्तिशाली ऑपरेटरों की पेशकश करता है जो सरल प्रतिस्थापन से परे हैं। इन मास्टरिंग से आपके मैक्रो को और भी अधिक लचीला बना सकते हैं।
] के साथ स्ट्रिंगिफिकेशन
] ऑपरेटर एक स्ट्रिंग साक्षर में एक मैक्रो तर्क बदल जाता है। यह डिबगिंग या लॉगिंग के लिए उपयोगी है:
#define PRINT_VAR(x) printf(#x " = %d\n", x)
int value = 42;
PRINT_VAR(value); // prints: value = 42
]] के साथ टोकन पेस्टिंग
] ऑपरेटर दो टोकनों को एक ही टोकन में जोड़ती है। इससे आपको पहचानकर्ता को संकलित समय पर गतिशील रूप से बनाने की अनुमति मिलती है:
#define CREATE_VAR(prefix, index) prefix ## index
int CREATE_VAR(arr, 0) = 10; // becomes int arr0 = 10;
Token pasting व्यापक रूप से X मैक्रोज़ में और दोहराए गए कोड पैटर्न के उत्पादन के लिए प्रयोग किया जाता है।
वैरिअडिक मैक्रोज़ (C99)
C99 में पेश किया गया, variadic मैक्रोज़ ] का उपयोग करके तर्कों की एक परिवर्तनीय संख्या स्वीकार करते हैं। यह लचीला लॉगिंग और मैक्रो को डीबगिंग करने में सक्षम बनाता है:
#define DEBUG_PRINT(fmt, ...) \
fprintf(stderr, "DEBUG: " fmt, __VA_ARGS__)
DEBUG_PRINT("x = %d, y = %d", x, y);
C11 में और बाद में, आप खाली तर्कों में ट्रेलिंग कम्युनिटी को संभालने के लिए का उपयोग कर सकते हैं, पोर्टेबिलिटी में सुधार कर सकते हैं।
Them से बचने के लिए कैसे
यहां तक कि अनुभवी सी डेवलपर्स ने मैक्रो से संबंधित बग का सामना किया। इन नुकसान को पहचानने से पहले सिरदर्द को रोका जा सकता है।
- ]Missing semicolons या braces: एक मैक्रो जो एक ट्रेलिंग सेमीकोल के बिना एक ब्लॉक में विस्तार करता है, वह वाक्यविन्यास त्रुटियों का कारण बन सकता है। ] पैटर्न इस हल को हल करता है।
- Operator precedence surprise: हमेशा Parenthesize-as noted ऊपर.
- ]]] कार्यों के साथ श्दोविंग मैक्रो : यदि आप एक मानक पुस्तकालय समारोह के रूप में उसी नाम के साथ एक मैक्रो को परिभाषित करते हैं, तो यह चुपचाप इसे ओवरराइड कर सकता है। अद्वितीय नामकरण या #undef का उपयोग करें।
- ]गैर-निरंतर प्रारंभिक [: वस्तु-जैसे मैक्रोज़ स्थिरांक के रूप में उपयोग किए जाते हैं, लेकिन उन्हें टाइप नहीं किया जाता है। उनका उपयोग केवल तभी किया जा सकता है जब विस्तार स्वयं एक निरंतर अभिव्यक्ति है।
- ]Debugging कठिनाई: Macros को विस्तार से पहले Compiler उन्हें देखता है, तो त्रुटि संदेश विस्तारित कोड का उल्लेख करते हैं, मैक्रो नाम नहीं। का उपयोग करके GCC या Clang के साथ ध्वज (जैसे, [[FLT: 29]]]) पता लगाने के मुद्दों के लिए पूर्व-प्रसाधित उत्पादन को दर्शाता है।
मैक्रोज़ के लिए विकल्प: const, enum, और इनलाइन कार्य
आधुनिक सी सुरक्षित विकल्प प्रदान करता है जो अक्सर मैक्रो की आवश्यकता को समाप्त करता है:
- ] ] चर : संख्यात्मक स्थिरांक के लिए, पसंद करते हैं। उनके पास उचित प्रकार की जाँच और सम्मान का दायरा है। हालांकि, वे सभी संदर्भों में संकलित समय-समय स्थिर नहीं हैं (उदाहरण के लिए, C90) में सरणी आकार। C99 और बाद में, का उपयोग सरणी आकार के लिए किया जा सकता है यदि चर वास्तव में स्थिर है (जैसे, [[FLT:]]])।
- ]]: संबंधित पूर्णांक स्थिरांक के एक सेट के लिए, enum प्रकार सुरक्षित हैं और स्वचालित रूप से मान निर्दिष्ट करते हैं। वे त्रुटि कोड और झंडे के लिए व्यापक रूप से उपयोग किए जाते हैं।
- ]Inline function: C99 में पेश किया गया, कार्यों में पूर्ण प्रकार की सुरक्षा, डीबगिंग समर्थन और साइड-प्रभाव मुद्दों से बचाव के साथ मैक्रो का प्रदर्शन प्रदान किया गया है। उदाहरण के लिए:
static inline int square(int x) {
return x * x;
}
जब भी आपको फ़ंक्शन की तरह मैक्रो की आवश्यकता होती है, तो केवल उन कार्यों का उपयोग करें जो एक बार तर्क का मूल्यांकन करते हैं। फंक्शन-जैसे मैक्रोज़ के लिए एकमात्र शेष उपयोग का मामला तब होता है जब आपको टाइप (जैसे, GNU C में टाइप) पर काम करने की आवश्यकता होती है या एक नया दायरा खोलने की क्षमता की आवश्यकता होती है (जैसे कि do-time मूर्खतापूर्ण)।
रियल-विश्व उदाहरण: डिबगिंग और कॉन्फ़िगरेशन
मैक्रोस सशर्त परिदृश्यों में उत्कृष्टता प्राप्त करते हैं। यहाँ दो व्यावहारिक अनुप्रयोग हैं:
Compile-Time Control के साथ लॉगिंग
#ifdef DEBUG
#define LOG(fmt, ...) fprintf(stderr, "[DEBUG] " fmt, ##__VA_ARGS__)
#else
#define LOG(fmt, ...) /* no-op */
#endif
यह मैक्रो लॉग केवल तभी होता है जब ] से संकलित किया गया है, और खाली मैक्रो रिलीज बिल्ड में शून्य ओवरहेड का कारण बनता है। [[FLT: 39]] पहले [[FLT: 40]] एक GNU एक्सटेंशन है जो किसी भी तर्क के बिना ट्रेलिंग कम्युनिटी को हटा देता है (जिसे C20 में [FLT: 41] के साथ भी समर्थन किया गया है)।
प्लेटफार्म-विशिष्ट कोड
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM "Windows"
#elif defined(__linux__)
#define PLATFORM "Linux"
#else
#define PLATFORM "Unknown"
#endif
यह पैटर्न पूरे कार्यों को दोहराए बिना मंच निर्भरता को अलग करता है। गार्ड के साथ संयुक्त, यह हेडर को साफ और बनाए रखने योग्य रखता है।
निष्कर्ष
मैक्रोज़ कोड पुन: प्रयोज्यता और रखरखाव के लिए सी में एक अनिवार्य उपकरण बने रहते हैं, विशेष रूप से प्रदर्शन-क्रिटिकल या एम्बेडेड संदर्भों में जहां हर चक्र की गिनती होती है। जब सही तरीके से उपयोग किया जाता है - उचित पैरेंटहेज़, सीमित दुष्प्रभाव और उचित नामकरण के साथ - वे दोहराव और केंद्रीयकरण विन्यास को कम करते हैं। हालांकि, आधुनिक सी में प्रवृत्ति अक्सर बेहतर हैं, जैसे कि इनलाइन कार्यों या जेनेरिक (Using ] C11) में टाइप सेफ्टी और डिबगबिलिटी हासिल करने के लिए कार्य-जैसे मैक्रोज़ को प्रतिस्थापित करना है।
इन सुरक्षित विकल्पों के साथ पारंपरिक मैक्रो पावर को संतुलित करके, आप C कोड लिख सकते हैं जो दोनों कुशल और मजबूत हैं। आगे पढ़ने के लिए, GNU C Preprocessor Manual] और ]C मैक्रोज़ ]] पर संदर्भ। विस्तार से मैक्रो पिटफॉल को समझना भी इस ]embedd.com article]] में शामिल है।