आधुनिक सी ++ विकास रुझान कोड में मैक्रोज़ की अधिकतम संभव अस्वीकृति का सुझाव देते हैं। लेकिन कभी-कभी मैक्रोज़ के बिना, और उनके विशेष रूप से बदसूरत अभिव्यक्ति में, कोई भी ऐसा नहीं कर सकता है, क्योंकि उनके बिना यह और भी बदतर है। इस बारे में और कहानी।
जैसा कि आप जानते हैं, सी और सी ++ को संकलित करने का पहला चरण प्रीप्रोसेसर है, जो मैक्रो और प्रीप्रोसेसर निर्देशों को सादे पाठ से बदल देता है।
यह हमें अजीब चीजें करने की अनुमति देता है, उदाहरण के लिए, जैसे:
प्रीप्रोसेसर के काम करने के बाद, यह गलतफहमी सही कोड में बदल जाएगी:
std::string str = "look, I'm a string!" ;
बेशक, इस भयानक हेडर को कहीं और शामिल नहीं किया जा सकता है। और हां, इस तथ्य के कारण कि हम इस हेडर को एक ही फ़ाइल में कई बार जोड़ देंगे - एक बार #pragma नहीं या गार्ड शामिल करें।
वास्तव में, आइए एक अधिक जटिल उदाहरण लिखें, जो मैक्रोज़ की मदद से अलग-अलग चीजें करेगा और साथ ही साथ यादृच्छिक रूप से बचाव करेगा:
यह अभी भी बदसूरत है, लेकिन एक निश्चित आकर्षण पहले से ही प्रकट होता है: जब आप एनम वर्ग में एक नया तत्व जोड़ते हैं, तो यह स्वचालित रूप से अतिभारित आउटपुट स्टेटमेंट में जोड़ा जाएगा।
यहां आप इस पद्धति के आवेदन के क्षेत्र को औपचारिक रूप दे सकते हैं: एक स्रोत के आधार पर विभिन्न स्थानों में कोड पीढ़ी की आवश्यकता।
और अब एक्स-मैक्रो और विंडोज की दुखद कहानी। विंडोज परफॉरमेंस काउंटर्स के रूप में एक ऐसी प्रणाली है, जो आपको ऑपरेटिंग सिस्टम में कुछ काउंटर भेजने की अनुमति देती है ताकि अन्य एप्लिकेशन उन्हें चुन सकें। उदाहरण के लिए, ज़ैबिक्स को किसी भी प्रदर्शन काउंटर को इकट्ठा करने और मॉनिटर करने के लिए कॉन्फ़िगर किया जा सकता है। यह काफी सुविधाजनक है, और आपको डेटा की वापसी / क्वेरी के साथ पहिया को सुदृढ़ करने की आवश्यकता नहीं है।
मैंने पूरी ईमानदारी से सोचा था कि एक नया काउंटर जोड़ने से एक ला HANDLE काउंटर = AddCounter ("नाम") दिखता है। आह, मैं कितना गलत था।
सबसे पहले आपको एक विशेष XML मेनिफ़ेस्ट (
उदाहरण ) लिखना होगा, या विंडोज SDK से ecmangen.exe प्रोग्राम का उपयोग करके इसे उत्पन्न करना होगा, लेकिन
किसी कारण से इस ecmangen
को Windows 10 SDK के नए संस्करणों से
हटा दिया गया है । इसके बाद, आपको हमारे XML मेनिफ़ेस्ट के आधार पर
ctrpp उपयोगिता का उपयोग करके कोड और .rc फ़ाइल जनरेट करनी होगी।
सिस्टम में नए काउंटरों को जोड़ना केवल
लॉकर में हमारे एक्सएमएल प्रकट होने के साथ
लॉकेट की उपयोगिता के साथ किया जाता है।
.Rc फ़ाइल क्या है?यह एक Microsoft आविष्कार है, जो मानक C ++ से संबंधित नहीं है। इन फ़ाइलों का उपयोग करके, आप exe \ dll में संसाधनों को एम्बेड कर सकते हैं, जैसे कि स्ट्रिंग \ icons \ चित्र, आदि, और फिर विशेष विंडोज एपीआई का उपयोग करके उन्हें उठाएं।
Perfcounters काउंटर नामों को स्थानीय करने के लिए इन .rc फ़ाइलों का उपयोग करते हैं, और यह बहुत स्पष्ट नहीं है कि इन नामों को स्थानीयकृत क्यों किया जाना चाहिए।
उपरोक्त सारांश: आप की जरूरत है 1 काउंटर जोड़ने के लिए:
- XML का प्रकटन बदलें
- प्रकट के आधार पर नए .c और .rc प्रोजेक्ट फ़ाइलों को जनरेट करें
- एक नया फ़ंक्शन लिखें जो एक नया काउंटर बढ़ाएगा
- एक नया फ़ंक्शन लिखें जो काउंटर वैल्यू लेगा
कुल: 4-5 संशोधित फाइलें एकल काउंटर के लिए और एक्सएमएल मेनिफेस्ट के साथ काम करने से लगातार पीड़ित होने के लिए, जो कि प्लस कोड में जानकारी का स्रोत है। यह वही है जो Microsoft हमें प्रदान करता है।
वास्तव में, आविष्कार किया गया उपाय डरावना लगता है, लेकिन एक नया काउंटर जोड़ना एक फ़ाइल में ठीक 1 पंक्ति में किया जाता है। इसके अलावा, सब कुछ स्वचालित रूप से मैक्रोज़ का उपयोग करके उत्पन्न होता है और, दुर्भाग्यवश, एक पूर्व-निर्मित स्क्रिप्ट, क्योंकि एक्सएमएल प्रकट अभी भी आवश्यक है, हालांकि अब यह मुख्य नहीं है।
हमारे perfcounters_ctr.h ऊपर दिए गए उदाहरण से लगभग समान दिखते हैं:
#ifndef NV_PERFCOUNTER #error "You cannot do this!" #endif ... NV_PERFCOUNTER(copied_bytes) NV_PERFCOUNTER(copied_files) ... #undef NV_PERFCOUNTER
जैसा कि मैंने पहले लिखा था, lodctr.exe का उपयोग करके XML प्रकट लोड करके काउंटरों को जोड़ना है। हमारे कार्यक्रम से, हम केवल उन्हें आरंभ और संशोधित कर सकते हैं।
जनरेटेड ओपनर में हमारे लिए अभिरुचि के प्रारंभिक अंश इस तरह दिखते हैं:
#define COPIED_BYTES 0
कुल: हमें प्रपत्र "काउंटर नाम - बढ़ते सूचकांक" के एक पत्राचार की आवश्यकता है, और संकलन चरण में काउंटरों की संख्या जानने और काउंटर सूचकांकों से एक आरंभीकरण सरणी एकत्र करना आवश्यक है। यह वह जगह है जहां एक्स-मैक्रो बचाव के लिए आता है।
इसके बढ़ते सूचकांक में एक काउंटर नाम से मिलान करना काफी सरल है।
नीचे दिया गया कोड एक एनम वर्ग में बदल जाएगा, जिसका आंतरिक सूचकांक 0 से शुरू होता है, और एक से बढ़ जाता है। अपने हाथों से अंतिम तत्व जोड़ने पर, हमें तुरंत पता चलता है कि हमारे पास कुल कितने काउंटर हैं:
enum class counter_enum : int { #define NV_PERFCOUNTER(ctr) ctr, #include "perfcounters_ctr.h" total_counters };
और आगे, हमारे एनम के आधार पर, हमें काउंटरों को इनिशियलाइज़ करने की आवश्यकता है:
static constexpr int counter_count = static_cast<int>(counter_enum::total_counters); const PERF_COUNTERSET_INFO counterset_info{ ... counter_count, ... }; struct { PERF_COUNTERSET_INFO set; PERF_COUNTER_INFO counters[counter_count]; } counterset { counterset_info, {
इसका नतीजा यह हुआ कि नए काउंटर के आरंभीकरण में अब 1 लाइन लगती है और अन्य फ़ाइलों में अतिरिक्त बदलाव की आवश्यकता नहीं होती है (पहले, प्रत्येक उत्थान ने प्रारंभ में कोड के 3 टुकड़े बदल दिए)।
और काउंटरों को बढ़ाने के लिए एक सुविधाजनक एपीआई जोड़ें। आत्मा में कुछ:
#define NV_PERFCOUNTER(ctr) \ inline void ctr##_tick(size_t diff = 1) { } #include "perfcounters_ctr.h" #define NV_PERFCOUNTER(ctr) \ inline size_t ctr##_get() { } #include "perfcounter_ctr.h"
प्रीप्रोसेसर हमारे लिए सुंदर गेटर्स / सेटर जनरेट करेगा, जिसे हम तुरंत कोड में उपयोग कर सकते हैं, उदाहरण के लिए:
inline void copied_bytes_tick(size_t diff = 1); inline size_t copied_bytes_get();
लेकिन हमारे पास अभी भी 2 दुखद बातें हैं: एक्सएमएल प्रकट और .rc फ़ाइल (अफसोस, यह आवश्यक है)।
हमने इसे काफी सरल बना दिया - एक पूर्व-निर्मित स्क्रिप्ट जो मूल फ़ाइल को मैक्रोज़ को परिभाषित करने वाले काउंटरों के साथ पढ़ती है, पर्स जो कि "NV_COUNTER (" और ")" के बीच है, और इसके आधार पर दोनों फाइलें जो कि .ignignore में हैं, उत्पन्न करता है। कूड़े अलग नहीं है।
यह था : एक्सएमएल प्रकट उत्पन्न कोडिंग कोड पर आधारित विशेष सॉफ्टवेयर। काउंटर के प्रत्येक जोड़ / हटाने के लिए परियोजना में बहुत सारे बदलाव।
अब: प्रीप्रोसेसर और प्रीलिफ्ट स्क्रिप्ट सभी काउंटर, XML प्रकट और .rc फ़ाइल उत्पन्न करती है। काउंटर को जोड़ने / हटाने के लिए अंतर-ई में बिल्कुल एक पंक्ति। प्रीप्रोसेसर के लिए धन्यवाद जिन्होंने इस समस्या को हल करने में मदद की, इस विशेष मामले में नुकसान की तुलना में अधिक अच्छा दिखा।