वैरिएड मैक्रो बनाने के लिए (तर्कों की चर संख्या)


196

मैं सी में एक मैक्रो लिखना चाहता हूं जो किसी भी संख्या में मापदंडों को स्वीकार करता है, एक विशिष्ट संख्या नहीं

उदाहरण:

#define macro( X )  something_complicated( whatever( X ) )

जहां Xमानकों के किसी भी संख्या है

मुझे इसकी आवश्यकता है क्योंकि whateverअतिभारित है और 2 या 4 मापदंडों के साथ बुलाया जा सकता है।

मैंने मैक्रो को दो बार परिभाषित करने की कोशिश की, लेकिन दूसरी परिभाषा ने पहले वाले को पछाड़ दिया!

संकलक मैं साथ काम कर रहा हूँ g ++ (अधिक विशेष रूप से, mingw)


8
क्या आप C या C ++ चाहते हैं? यदि आप C का उपयोग कर रहे हैं, तो आप C ++ कंपाइलर का संकलन क्यों कर रहे हैं? उचित C99 वैरिएड मैक्रोज़ का उपयोग करने के लिए, आपको C संकलक के साथ संकलित करना चाहिए जो C99 (जैसे gcc) का समर्थन करता है, C ++ संकलक नहीं, क्योंकि C ++ में मानक वैरिएड मैक्रो नहीं है।
क्रिस लुत्ज़

ठीक है, मैं सी ग्रहण ++ इस संबंध में सी के एक सुपर सेट .. है
Hasen

tigcc.ticalc.org/doc/cpp.html#SEC13 में वैराडिक मैक्रो का विस्तृत विवरण है।
Gnubie

एक अच्छी व्याख्या और उदाहरण यहाँ है http://gcc.gnu.org/oniltocs/cpp/Variadic-Macros.html
zafarulq

3
भविष्य के पाठकों के लिए: C , C ++ का उप-समूह नहीं है। वे कई बातें साझा करते हैं, लेकिन ऐसे नियम हैं जो उन्हें एक दूसरे की सबसेट और सुपरसेट होने से रोकते हैं।
फाप्र

जवाबों:


295

C99 तरीका, जो VC ++ कंपाइलर द्वारा भी समर्थित है।

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)

8
मुझे नहीं लगता कि VA_ARGS से पहले C99 को ## की आवश्यकता है । वह सिर्फ VC ++ हो सकता है।
क्रिस लुत्ज़

98
VA_ARGS से पहले ## का कारण यह है कि चर-तर्क सूची खाली होने की स्थिति में पूर्ववर्ती अल्पविराम निगल जाता है, जैसे। FOO ("a") प्रिंटफ ("a") तक फैलता है। यह gcc (और vc ++, हो सकता है) का एक विस्तार है, C99 को दीर्घवृत्त के स्थान पर मौजूद होने के लिए कम से कम एक तर्क की आवश्यकता होती है।
jpalecek

109
##जरूरत नहीं है और पोर्टेबल नहीं है। #define FOO(...) printf(__VA_ARGS__)पोर्टेबल तरीके से काम करता है; fmtपैरामीटर परिभाषा से बाहर रखा जा सकता है।
एलेकोव

4
IIRC, ## GCC विशिष्ट है और शून्य मापदंडों को पारित करने की अनुमति देता है
Mawg का कहना है कि मोनिका

10
## - सिंटैक्स llvm / clang और Visual Studio कंपाइलर के साथ भी काम करता है। तो यह पोर्टेबल नहीं हो सकता है, लेकिन यह प्रमुख संकलक द्वारा समर्थित है।
। बर्मन ने

37

__VA_ARGS__इसे करने का मानक तरीका है। यदि आपके पास करने के लिए संकलक-विशिष्ट हैक्स का उपयोग न करें।

मैं वास्तव में नाराज हूं कि मैं मूल पोस्ट पर टिप्पणी नहीं कर सकता। किसी भी मामले में, C ++, C का सुपरसेट नहीं है। C ++ कंपाइलर के साथ अपने C कोड को संकलित करना वास्तव में मूर्खतापूर्ण है। डोनी मत करो मत करो।


8
"सी ++ कंपाइलर के साथ अपने सी कोड को संकलित करना वास्तव में मूर्खतापूर्ण है" => ऐसा हर किसी के द्वारा नहीं माना जाता है (मेरे सहित)। उदाहरण के लिए C ++ कोर दिशानिर्देश देखें: CPL.1: C ++ को C , CPL.2 को प्राथमिकता दें: यदि आपको C का उपयोग करना है, तो C और C ++ के सामान्य सबसेट का उपयोग करें, और C कोड को C ++ के रूप में संकलित करें । मुझे लगता है कि "C-only-isms" के बारे में सोचने के लिए मुझे कड़ी मेहनत करनी पड़ती है, जिसे वास्तव में संगत उप-क्रम में प्रोग्रामिंग के लायक नहीं बनाने की आवश्यकता होती है, और C और C ++ समितियों ने उस संगत उप-उपलब्ध को बनाने में कड़ी मेहनत की है।
HostileFork का कहना है कि SE

4
@HostileFork मेले पर्याप्त है, हालांकि निश्चित रूप से सी ++ लोगों सी के उपयोग ++ प्रोत्साहित करने के लिए करना चाहते हैं। अन्य लोग असहमत हैं, हालांकि; उदाहरण के लिए, लिनक्स टोरवाल्ड्स ने स्पष्ट रूप से कई प्रस्तावित लिनक्स-कर्नेल पैच को अस्वीकार कर दिया है जो पहचानकर्ता classको klassसी ++ संकलक के साथ संकलित करने की अनुमति देने का प्रयास करता है। यह भी ध्यान दें कि कुछ अंतर हैं जो आपको यात्रा करेंगे; उदाहरण के लिए, दोनों भाषाओं में एक ही तरह से टर्नरी ऑपरेटर का मूल्यांकन नहीं किया जाता है, और inlineकीवर्ड का अर्थ कुछ अलग है (जैसा कि मैंने एक अलग प्रश्न से सीखा है)।
काइल स्ट्रैंड

3
ऑपरेटिंग सिस्टम की तरह वास्तव में क्रॉस-प्लेटफॉर्म सिस्टम प्रोजेक्ट के लिए, आप वास्तव में सख्त सी का पालन करना चाहते हैं, क्योंकि सी कंपाइलर्स बहुत अधिक सामान्य हैं। एम्बेडेड सिस्टम में, C ++ कंपाइलर के बिना अभी भी प्लेटफार्म हैं। (केवल पास करने योग्य C कंपाइलर के साथ प्लेटफ़ॉर्म हैं!) C ++ कंपाइलर मुझे परेशान करते हैं, विशेष रूप से साइबर-भौतिक प्रणालियों के लिए, और मुझे लगता है कि मैं उस भावना के साथ केवल एम्बेडेड सॉफ़्टवेयर / सी प्रोग्रामर नहीं हूं।
डाउनबीट

2
@downbeat आप उत्पादन के लिए C ++ का उपयोग करते हैं या नहीं, अगर यह आपके बारे में चिंतित है, तो C ++ के साथ संकलन करने में सक्षम होने से आपको स्थैतिक विश्लेषण के लिए जादुई शक्तियां मिलती हैं। यदि आपके पास एक क्वेरी है जिसे आप सी कोडबेस बनाना चाहते हैं ... सोच रहे हैं कि क्या कुछ प्रकारों का उपयोग कुछ निश्चित तरीकों से किया जाता है, तो टाइप_ट्रीट का उपयोग करना सीखना इसके लिए लक्षित टूल का निर्माण कर सकता है। C के स्थैतिक विश्लेषण उपकरण के लिए आप जो बड़ा पैसा देंगे, वह C ++ की थोड़ी
मात्रा के

1
मैं लिनक्स के सवाल पर बोल रहा हूँ। (मैंने अभी देखा कि यह "लिनक्स टॉर्वाल्ड्स" हा कहता है!)
डाउनबीट

28

मुझे नहीं लगता कि यह संभव है, आप इसे डबल पार्न्स के साथ नकली कर सकते हैं ... जब तक आपको व्यक्तिगत रूप से तर्कों की आवश्यकता नहीं है।

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))

21
जबकि एक वैरिएड मैक्रो होना संभव है, डबल कोष्ठक का उपयोग करना एक अच्छी सलाह है।
डेविड रॉड्रिग्ज - dribeas

2
माइक्रोचिप द्वारा XC कंपाइलर वैरिएड मैक्रोज़ का समर्थन नहीं करता है, और इसलिए यह डबल कोष्ठक चाल सबसे अच्छा है जो आप कर सकते हैं।
gbmhunter

10
#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

यदि कंपाइलर वैरिएड मैक्रोज़ को नहीं समझता है, तो आप निम्नलिखित में से किसी एक के साथ प्रिंट को भी निकाल सकते हैं:

#define PRINT //

या

#define PRINT if(0)print

पहला कमेंट PRINT निर्देशों से बाहर है, दूसरा NULL की शर्त के कारण PRINT इंस्ट्रक्शन को रोकता है। यदि ऑप्टिमाइज़ेशन सेट किया गया है, तो कंपाइलर को कभी भी निष्पादित निर्देशों का पालन नहीं करना चाहिए जैसे: यदि (0) प्रिंट ("हैलो वर्ल्ड"); या ((शून्य) 0);


8
#define PRINT //
bit

8
#define प्रिंट अगर (0) प्रिंट एक अच्छा विचार नहीं है, क्योंकि कॉलिंग कोड का अपना दूसरा हो सकता है-अगर कॉल को प्रिंट करने के लिए। बेहतर है: #define प्रिंट अगर (सच); नहीं तो प्रिंट करें
बिटकॉइन

3
मानक "कुछ भी नहीं, इनायत से" करना है {} जबकि (0)
वॉनब्रांड

ifकोड संरचना को ध्यान में रखते हुए "ऐसा न करें" का उचित संस्करण है: if (0) { your_code } elseआपके स्थूल विस्तार के समाप्त होने के बाद एक अर्ध-बृहदान्त्र elsewhileसंस्करण लगता है: while(0) { your_code } के साथ इस मुद्दे do..whileसंस्करण है कि कोड में है do { your_code } while (0)एक बार किया जाता है, की गारंटी। तीनों मामलों में, यदि your_codeखाली है, तो यह उचित है do nothing gracefully
जेसी चिशोल्म

4

यहाँ जी ++ के लिए समझाया गया है, हालांकि यह C99 का हिस्सा है इसलिए सभी के लिए काम करना चाहिए

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

त्वरित उदाहरण:

#define debug(format, args...) fprintf (stderr, format, args)

3
GCC के वैरेडिक मैक्रो C99 वैरेडिक मैक्रो नहीं हैं। GCC में C99 वैरिएड मैक्रोज़ हैं, लेकिन G ++ उनका समर्थन नहीं करता है, क्योंकि C99 C ++ का हिस्सा नहीं है।
क्रिस लुत्ज़

1
वास्तव में g ++ C ++ फाइलों में C99 मैक्रो को संकलित करेगा। यह एक चेतावनी जारी करेगा, हालांकि, अगर '-तीसारी' के साथ संकलित किया जाता है।
एलेक्स बी

2
यह C99 नहीं है। C99 VA_ARGS मैक्रो का उपयोग करें )।
qrdl

1
C ++ 11 भी समर्थन करता है __VA_ARGS__, हालांकि वे एक विस्तार के रूप में पुराने संस्करणों में संकलक द्वारा समर्थित हैं।
इथोरिस

1
यह प्रिंटफ ("हाय") के लिए काम करने में विफल रहता है; जहाँ कोई var args नहीं हैं। इसे ठीक करने का कोई सामान्य तरीका?
BTR नायडू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.