कैसे, वास्तव में, डबल-स्ट्रिंग चाल काम करती है?


84

कम से कम कुछ C प्रीप्रोसेसरों ने आपको एक मैक्रो के मान को उसके नाम के बजाय एक फ़ंक्शन-जैसे मैक्रो के माध्यम से दूसरे से गुजरने से रोक दिया है जो इसे स्ट्रिंग करता है:

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */

उदाहरण यहाँ मामलों का उपयोग करें

यह कम से कम जीसीसी और क्लैंग (दोनों के साथ -std=c99) में काम करता है , लेकिन मुझे यकीन नहीं है कि यह सी-मानक शब्दों में कैसे काम करता है।

क्या यह व्यवहार C99 द्वारा गारंटीकृत है?
यदि हां, तो C99 इसकी गारंटी कैसे देता है?
यदि नहीं, तो किस बिंदु पर व्यवहार सी-परिभाषित से जीसीसी-परिभाषित होता है?


1
यदि आप "कम से कम कुछ" कहते हैं, तो क्या इसका मतलब है कि आपने एक देखा है जहां यह काम नहीं करता है? मैं विक्रेता को एक बग रिपोर्ट लिखने को तैयार हूं।
जेन्स

@ जेन्स: नहीं; मैंने नहीं किया है मेरे द्वारा उपयोग किए गए प्रत्येक कंपाइलर (अर्थात्, जीसीसी और क्लैंग) इस व्यवहार को लागू करते हैं।
पीटर होसी

जवाबों:


80

हाँ, इसकी गारंटी है।

यह काम करता है क्योंकि मैक्रोज़ के तर्क स्वयं मैक्रो-विस्तारित हैं, सिवाय इसके कि मैक्रो लॉजिक नाम स्ट्रिंगर # या टोकन-पेस्टर ## के साथ मैक्रो बॉडी में प्रकट होता है।

6.10.3.1/1:

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

इसलिए, यदि आप करते हैं STR1(THE_ANSWER)तो आपको "THE_ANSWER" मिलता है, क्योंकि STR1 का तर्क मैक्रो-विस्तारित नहीं है। हालाँकि, STR2 का तर्क स्थूल-विस्तारित है, जब इसे STR2 की परिभाषा में प्रतिस्थापित किया जाता है, जो 42"42" के परिणाम के साथ, STR1 को एक तर्क देता है ।


21

स्टीव नोट के रूप में, यह ग्वारेंटेड है, और यह C89 मानक के बाद से ग्वारेंटेड है - यही मानक मैक्रोज़ में # और ## ऑपरेटरों को संहिताबद्ध किया गया था और जनादेश में मैक्रोज़ का आवर्ती विस्तार करते हुए उन्हें शरीर में प्रतिस्थापित करने से पहले अगर और केवल अगर शरीर तर्क पर # या ## लागू नहीं करता है। C99 इस संबंध में C89 से अपरिवर्तित है।


+1 यह पुष्टि करने के लिए कि यह C89 का भी हिस्सा है। हम में से कुछ पोर्टेबिलिटी की परवाह करते हैं, जिसमें कोड बनाना शामिल है जिसे C89 मोड में संकलन करने वाले लोग उपयोग कर सकते हैं - अभी कुछ साल पहले gcc अभी भी C89 (निष्पक्ष होने के लिए प्लस एक्सटेंशन) के लिए डिफ़ॉल्ट रूप से जारी है, MSVC पिछले मैंने अभी भी केवल C89 का समर्थन करते हुए सुना, और एम्बेडेड या विरासत प्रणालियों में भी कभी-कभी केवल C89 संकलक होते हैं। C89 एक महान पोर्टेबिलिटी "ग्राउंड फ्लोर" के लिए बनाता है, एक न्यूनतम सामान्य भाजक मानक जिसे लोग आज व्यावहारिक उपयोग में किसी भी चीज के लिए संकलन और चलाने के लिए लक्षित कर सकते हैं। इसलिए इसे याद करके देखना बहुत अच्छा लगता है।
मत्तुर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.