मैक्रों किसी भी अन्य उपकरण की तरह हैं - एक हथौड़ा का इस्तेमाल एक हत्या में बुराई नहीं है क्योंकि यह एक हथौड़ा है। यह उस तरीके से बुराई है जिस तरह से व्यक्ति इसका इस्तेमाल करता है। यदि आप नाखूनों में हथौड़ा मारना चाहते हैं, तो एक हथौड़ा एक आदर्श उपकरण है।
मैक्रोज़ के कुछ पहलू हैं जो उन्हें "खराब" बनाते हैं (मैं प्रत्येक बाद में विस्तार करूंगा, और विकल्प सुझाऊंगा):
- आप मैक्रोज़ को डिबग नहीं कर सकते।
- मैक्रो विस्तार से अजीब दुष्प्रभाव हो सकते हैं।
- मैक्रोज़ का कोई "नेमस्पेस" नहीं है, इसलिए यदि आपके पास एक मैक्रो है जो किसी अन्य जगह इस्तेमाल किए गए नाम के साथ टकराता है, तो आपको मैक्रो प्रतिस्थापन मिलते हैं जहां आप इसे नहीं चाहते थे, और यह आमतौर पर अजीब त्रुटि संदेशों की ओर जाता है।
- मैक्रोज़ उन चीजों को प्रभावित कर सकते हैं जिन्हें आप महसूस नहीं करते हैं।
तो चलिए यहाँ थोड़ा विस्तार करते हैं:
1) मैक्रोज़ को डीबग नहीं किया जा सकता है।
जब आपके पास एक मैक्रो होता है जो किसी संख्या या स्ट्रिंग में अनुवाद करता है, तो स्रोत कोड में मैक्रो नाम और कई डीबगर्स होंगे, आप मैक्रो का अनुवाद करने के लिए "नहीं" देख सकते हैं। तो आप वास्तव में नहीं जानते कि क्या चल रहा है।
प्रतिस्थापन : उपयोग enumयाconst T
"फ़ंक्शन-लाइक" मैक्रोज़ के लिए, क्योंकि डीबगर "प्रति स्रोत रेखा जहां आप हैं" स्तर पर काम करता है, आपका मैक्रो एकल कथन की तरह काम करेगा, चाहे वह एक बयान या सौ ही क्यों न हो। यह पता लगाना मुश्किल है कि क्या चल रहा है।
प्रतिस्थापन : उपयोग कार्य - इनलाइन यदि इसे "तेज़" करने की आवश्यकता है (लेकिन सावधान रहें कि बहुत अधिक इनलाइन एक अच्छी बात नहीं है)
2) मैक्रो विस्तार में अजीब दुष्प्रभाव हो सकते हैं।
प्रसिद्ध एक है #define SQUARE(x) ((x) * (x))और उपयोग x2 = SQUARE(x++)। इसके कारण x2 = (x++) * (x++);, जो, भले ही यह मान्य कोड [1] था, लगभग निश्चित रूप से वह नहीं होगा जो प्रोग्रामर चाहता था। यदि यह एक फ़ंक्शन था, तो x ++ करना ठीक होगा, और x केवल एक बार वेतन वृद्धि करेगा।
एक और उदाहरण मैक्रोज़ में "यदि और" है, तो कहें कि हमारे पास यह है:
#define safe_divide(res, x, y) if (y != 0) res = x/y;
और फिर
if (something) safe_divide(b, a, x);
else printf("Something is not set...");
यह वास्तव में पूरी तरह से गलत बात बन जाती है…।
प्रतिस्थापन : वास्तविक कार्य।
3) मैक्रों का कोई नामस्थान नहीं है
यदि हमारे पास एक मैक्रो है:
#define begin() x = 0
और हमारे पास C ++ में कुछ कोड हैं जो शुरू का उपयोग करते हैं:
std::vector<int> v;
... stuff is loaded into v ...
for (std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
std::cout << ' ' << *it;
अब, आपको क्या त्रुटि संदेश लगता है कि आप प्राप्त करते हैं, और आप एक त्रुटि कहां देखते हैं [यह मानते हुए कि आप पूरी तरह से भूल गए हैं - या इसके बारे में भी नहीं जानते हैं - शुरुआत मैक्रो जो किसी हेडर फ़ाइल में रहता है जो किसी और ने लिखा है? [और इससे भी ज्यादा मजेदार अगर आप उस मैक्रो को शामिल करने से पहले शामिल करते हैं - आप अजीब त्रुटियों में डूब जाते हैं जो कोड को देखते समय बिल्कुल कोई मतलब नहीं रखता है।
प्रतिस्थापन : वैसे "नियम" के रूप में प्रतिस्थापन के लिए इतना कुछ नहीं है - केवल मैक्रोज़ के लिए अपरकेस नामों का उपयोग करें, और अन्य चीजों के लिए सभी अपरकेस नामों का उपयोग कभी न करें।
4) मैक्रोज़ के प्रभाव आप महसूस नहीं करते हैं
यह कार्य करें:
#define begin() x = 0
#define end() x = 17
... a few thousand lines of stuff here ...
void dostuff()
{
int x = 7;
begin();
... more code using x ...
printf("x=%d\n", x);
end();
}
अब, मैक्रो को देखे बिना, आप सोचेंगे कि शुरुआत एक फ़ंक्शन है, जो x को प्रभावित नहीं करना चाहिए।
इस तरह की बात, और मैंने बहुत अधिक जटिल उदाहरण देखे हैं, क्या वास्तव में आपके दिन को गड़बड़ कर सकता है!
प्रतिस्थापन : x को सेट करने के लिए किसी मैक्रो का उपयोग न करें, या x को तर्क के रूप में पास करें।
ऐसे समय होते हैं जब मैक्रोज़ का उपयोग करना निश्चित रूप से फायदेमंद होता है। एक उदाहरण फ़ाइल / लाइन की जानकारी को पारित करने के लिए मैक्रोज़ के साथ एक फ़ंक्शन लपेटना है:
#define malloc(x) my_debug_malloc(x, __FILE__, __LINE__)
#define free(x) my_debug_free(x, __FILE__, __LINE__)
अब हम my_debug_mallocकोड में नियमित मॉलोक के रूप में उपयोग कर सकते हैं , लेकिन इसके पास अतिरिक्त तर्क हैं, इसलिए जब यह अंत में आता है और हम "जो स्मृति तत्वों को मुक्त नहीं किया गया है" को स्कैन करते हैं, हम प्रिंट कर सकते हैं कि आवंटन कहाँ बनाया गया था प्रोग्रामर लीक को ट्रैक कर सकता है।
[१] एक अनुक्रम में "एक अनुक्रम बिंदु में" एक से अधिक चर को अद्यतन करने के लिए यह अपरिभाषित व्यवहार है। एक अनुक्रम बिंदु एक बयान के समान नहीं है, लेकिन अधिकांश इरादों और उद्देश्यों के लिए, यही हमें इस पर विचार करना चाहिए। तो ऐसा करने x++ * x++से xदो बार अपडेट होगा , जो अपरिभाषित है और संभवत: विभिन्न प्रणालियों पर अलग-अलग मान और xसाथ ही साथ अलग-अलग परिणाम मान देगा ।
#pragmaस्थूल नहीं है।