2011-11-22 12 views
23

में: C++ FAQ - Miscellaneous technical issues - [39.6] What should be done with macros that need to paste two tokens together?मैक्रोज़ के लिए मुझे संकेत की डबल परत की आवश्यकता क्यों है?

कोई मुझे क्यों को समझा सकते हैं? मैंने पढ़ा है मुझे पर भरोसा है, लेकिन मैं बस किसी चीज़ पर भरोसा नहीं कर सकता क्योंकि किसी ने ऐसा कहा था।

मैं दृष्टिकोण की कोशिश की और मैं किसी भी कीड़े दिखाई नहीं दे पा सकते हैं:

#define mymacro(a) int a ## __LINE__ 
mymacro(prefix) = 5; 
mymacro(__LINE__) = 5; 
int test = prefix__LINE__*__LINE____LINE__; // fine 

तो क्यों मैं (वेबपेज से उद्धरण) के बजाय इस तरह यह क्या करना होगा:

हालांकि जब आप ## का उपयोग करते हैं तो आपको संकेत की एक डबल परत की आवश्यकता होती है। मूल रूप से आप इस तरह के के रूप में "टोकन चिपकाने" के लिए एक विशेष मैक्रो बनाना होगा: इस पर

#define NAME2(a,b)   NAME2_HIDDEN(a,b) 
#define NAME2_HIDDEN(a,b) a ## b 

ट्रस्ट मुझे - क्या तुम सच में यह करने के लिए की जरूरत है! (और किसी ने मुझे कहा कि यह कभी कभी अविवेक की दूसरी परत के बिना काम करता लिखें __ LINE__ के साथ एक प्रतीक श्रृंखलाबद्ध की कोशिश करो और देखो क्या तब होता है।।)

संपादित करें: किसी भी समझा सकते हैं कि क्यों वह का उपयोग करता है NAME2_HIDDEN नीचे घोषित करने से पहले? इसका उपयोग करने से पहले NAME2_HIDDEN मैक्रो को परिभाषित करने के लिए यह अधिक तार्किक लगता है। क्या यह यहां कुछ प्रकार की चाल है?

+0

मुझे यकीन नहीं है कि मैं समझ रहा हूं कि आप क्या पूछ रहे हैं ... –

+0

मैं इसे थोड़ा अस्पष्ट देखता हूं, मैं संपादित करूंगा। – Rookie

+0

@tenfour, किया। क्या आप मेरे संपादन भाग का जवाब जान सकते हैं? – Rookie

उत्तर

29

सी कल्पना की प्रासंगिकता का:

6.10.3.1 तर्क प्रतिस्थापन

एक समारोह की तरह मैक्रो के आह्वान के लिए बहस के बाद पहचान की गई है, तर्क प्रतिस्थापन जगह लेता है। प्रतिस्थापन सूची में एक पैरामीटर, से पहले # या ## प्रीप्रोकैसिंग टोकन द्वारा या ## प्रीप्रोकैसिंग टोकन (नीचे देखें) के बाद, उसमें निहित सभी मैक्रोज़ विस्तारित होने के बाद संबंधित तर्क द्वारा प्रतिस्थापित किया गया है। प्रतिस्थापित होने से पहले, प्रत्येक तर्क के प्रीप्रोकैसिंग टोकन पूरी तरह से मैक्रो प्रतिस्थापित होते हैं जैसे कि उन्होंने शेष प्रीप्रोकैसिंग फ़ाइल बनाई है; कोई अन्य प्रीप्रोकैसिंग टोकन उपलब्ध हैं।

महत्वपूर्ण हिस्सा निर्धारित करता है कि चाहे आप डबल अविवेक चाहते हैं या नहीं दूसरे वाक्य और उस में अपवाद नहीं है - अगर पैरामीटर (जैसे mymacro और NAME2_HIDDEN में पैरामीटर के रूप में एक # या ## आपरेशन में शामिल है), तो तर्क में किसी अन्य मैक्रोज़ को # या ## करने से पहले विस्तारित नहीं किया गया है।यदि, दूसरी ओर, मैक्रो बॉडी में या ## तुरंत नहीं है (NAME2 के साथ), तो पैरामीटर में अन्य मैक्रोज़ विस्तारित हैं।

तो यह तुम क्या चाहते करने के लिए नीचे आता है - कभी कभी आप सभी मैक्रो पहले विस्तार चाहते हैं और फिर कर # या ## (इस स्थिति में आप डबल परत अविवेक चाहते हैं) और कुछ समय आप करते नहीं चाहते मैक्रो पहले विस्तार (जिस स्थिति में आप डबल लेयर मैक्रोज़ नहीं कर सकते हैं, आपको इसे सीधे करने की आवश्यकता है।)

+1

। मैंने इसे बहुत परेशान पाया, वेबसाइट ने मुझे हमेशा इसका इस्तेमाल करने के लिए कहा ... जबकि मेरे मामले में मैं इसे इस तरह से कभी भी उपयोग नहीं करना चाहता। – Rookie

4

__LINE__ एक विशेष मैक्रो है जो वर्तमान पंक्ति संख्या को हल करने के लिए माना जाता है। जब आप सीधे __LINE__ के साथ टोकन पेस्ट करते हैं, तो इसे हल करने का मौका नहीं मिलता है, इसलिए आप prefix23 के बजाय टोकन prefix__LINE__ के साथ समाप्त हो जाते हैं, जैसे कि आप शायद यह उम्मीद कर रहे होंगे कि आप इस कोड को लिखेंगे जंगली।

+0

संपादित करें: ओह रुको, आपका मतलब है कि कोई वैरिएबल नाम में लाइन नंबर देने की अपेक्षा करेगा? हम्म अच्छी तरह से। क्या यह तब सभी समस्याओं का कारण बन जाएगा? – Rookie

+0

क्या आप यह भी समझा सकते हैं कि उन्होंने "गलत" क्रम में मैक्रोज़ का उपयोग क्यों किया है? जैसे। वह घोषित होने से पहले मैक्रो 'NAME2_HIDDEN' को संदर्भित करता है। क्या यह अच्छा अभ्यास माना जाता है, या यह किसी तरह की चाल है? मैंने दोनों तरीकों का परीक्षण किया और मुझे एक ही परिणाम मिलते हैं। – Rookie

+0

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

3

क्रिस डोड के आपके प्रश्न के पहले भाग के लिए एक उत्कृष्ट स्पष्टीकरण है। दूसरे भाग के लिए, परिभाषा अनुक्रम के बारे में, लघु संस्करण यह है कि #define स्वयं द्वारा निर्देशों का मूल्यांकन नहीं किया जाता है; जब फ़ाइल में कहीं और पाया जाता है तो उनका मूल्यांकन और विस्तार किया जाता है। उदाहरण के लिए:

#define A a //adds A->a to the symbol table 
#define B b //adds B->b to the symbol table 

int A; 

#undef A  //removes A->a from the symbol table 
#define A B //adds A->B to the symbol table 

int A; 

पहले int A;int a; हो जाता है क्योंकि है कि कैसे A फाइल में उस बिंदु पर परिभाषित किया गया है। दो विस्तार के बाद दूसरा int A;int b; बन जाता है। इसे पहले int B; तक बढ़ाया गया है क्योंकि A को फ़ाइल में उस बिंदु पर B के रूप में परिभाषित किया गया है। प्रीप्रोसेसर तब पहचानता है कि B एक मैक्रो है जब यह प्रतीक तालिका की जांच करता है। B को तब b पर विस्तारित किया गया है।

परिभाषा के बिंदु पर प्रतीक की परिभाषा एकमात्र चीज है जो परिभाषा के बिंदु पर प्रतीक की परिभाषा है।

+1

ओह हाँ, मैंने सोचा कि उन्हें उस क्रम में रखने के लिए और अधिक तार्किक होगा जहां आप उनका उपयोग करते हैं, किसी भी तरह से मुझे और अधिक समझ में आता है। समझाने के लिए धन्यवाद। – Rookie

1

जिस क्रम में मैक्रोज़ घोषित किए गए हैं, वह महत्वपूर्ण नहीं है, जिस क्रम में उनका उपयोग किया जाता है वह है। यदि आप वास्तव में घोषित किए जाने से पहले उस मैक्रो का उपयोग करना चाहते थे - (वास्तविक कोड में, एक मैक्रो में नहीं जो कि बुलाए जाने तक निष्क्रिय रहता है) तो आपको एक प्रकार की त्रुटि मिल जाएगी लेकिन चूंकि अधिकतर लोग लोग चारों ओर नहीं जाते हैं इस तरह की चीजें, एक मैक्रो लिखना और फिर एक ऐसा फ़ंक्शन लिखना जो मैक्रो का उपयोग करता है, अभी तक नीचे परिभाषित नहीं किया गया है, आदि ... ऐसा लगता है कि आपका प्रश्न केवल एक प्रश्न नहीं है, लेकिन मैं बस उस हिस्से का जवाब दूंगा। मुझे लगता है कि आपको इसे थोड़ा और तोड़ना चाहिए था।

0

सबसे गैर-तकनीकी उत्तर, जिसे मैंने यहां सभी लिंक से एकत्र किया है, और लिंक का लिंक;) यह है कि, एक परत परत संकेत macro(x) #x इनपुट मैक्रो के नाम को स्ट्रिंग करता है, लेकिन डबल परतों का उपयोग करके, यह इनपुट को स्ट्रिंग करेगा मैक्रो का मूल्य

#define valueOfPi 3 
#define macroHlp(x) #x 
#define macro(x) macroHlp(x) 
#define myVarOneLayer "Apprx. value of pi = " macroHlp(valueOfPi) 
#define myVarTwoLayers "Apprx. value of pi = " macro(valueOfPi) 

printf(myVarOneLayer); // out: Apprx. value of pi = valueOfPi 
printf(myVarOTwoLayers); // out: Apprx. value of pi = 3 

क्या printf(myVarOneLayer)

printf(myVarOneLayer) में क्या होता है इनपुट stringify को printf("Apprx. value of pi = " macroHlp(valueOfPi))

macroHlp(valueOfPi) की कोशिश करता करने के लिए विस्तारित किया गया है, इनपुट खुद का मूल्यांकन नहीं किया गया है। जीवन में इसका एकमात्र उद्देश्य इनपुट और स्ट्रिंग करना है। तो यह "valueOfPi"

तो करने के लिए फैलता है, क्या printf(myVarTwoLayers)

printf(myVarTwoLayers) में क्या होता है printf("Apprx. value of pi = " macro(valueOfPi)

macro(valueOfPi) करने के लिए विस्तारित किया गया है कोई stringification आपरेशन, यानी इसमें विस्तार है में है कोई #x है, लेकिन वहाँ एक x है, इसलिए इसे x का मूल्यांकन करना है और स्ट्रिंग के लिए macroHlp पर मान इनपुट करना है।यह macroHlp(3) तक फैलता है जो बदले में नंबर 3 को स्ट्रिंग करेगा, क्योंकि यह #x

संबंधित मुद्दे