2012-01-06 15 views
10

मेरे पास एक ऐसा फ़ंक्शन है जिसे मुझे मैक्रोज़ करने की आवश्यकता है। फ़ंक्शन में अस्थायी चर शामिल हैं और मैक्रो प्रतिस्थापन में अस्थायी चर के उपयोग के बारे में कोई नियम हैं, तो मुझे याद नहीं है।क्या सी मैक्रो में अस्थायी चर शामिल हो सकते हैं?

long fooAlloc(struct foo *f, long size) 
{ 
    long  i1, i2; 
    double *data[7]; 

    /* do something */ 
    return 42; 
} 

मैक्रो प्रपत्र:

#define ALLOC_FOO(f, size) \ 
{\ 
    long  i1, i2;\ 
    double *data[7];\ 
\ 
    /* do something */ \ 
} 

यह ठीक है? (यानी कोई बुरा दुष्प्रभाव नहीं - सामान्य लोगों के अलावा: "सुरक्षित टाइप करें" आदि)। बीटीडब्ल्यू, मुझे पता है कि "मैक्रोज़ बुराई हैं" - मुझे बस इस मामले में इसका उपयोग करना होगा - ज्यादा पसंद नहीं।

+3

आप की जरूरत क्यों है इसे मैक्रोराइज करें? यदि आप प्रदर्शन के बारे में चिंतित हैं, तो (ए) संभावना है कि आप अनावश्यक रूप से चिंता कर रहे हैं (जब तक कि आपने वास्तव में इसे माप लिया न हो और निष्कर्ष निकाला कि यह एक महत्वपूर्ण बाधा है) और (बी) आप एक ही प्रकार में एक ही प्रभाव प्राप्त कर सकते हैं -इस तरीके से, फ़ंक्शन 'इनलाइन' बनाकर (कुछ पुराने या माइक्रोसॉफ्ट कंपाइलर्स इसका समर्थन नहीं कर सकते हैं)। –

+3

@ किथहॉम्पसन प्रदर्शन यहां मुद्दा नहीं है। मैं एक विस्तार पुस्तकालय लिख रहा हूं और मुझे कुछ डेटा मार्शलिंग करने के लिए एक रैपर फ़ंक्शन की आवश्यकता है। मैक्रोज़ स्वचालित रूप से बहुत से "गोंद" कोड उत्पन्न करने के लिए एक कम त्रुटि प्रवण तरीका प्रदान करते हैं। –

+0

मैक्रो के अंदर 'वापसी' ऐसा नहीं करता जो आपको लगता है कि ऐसा लगता है। –

उत्तर

24

केवल दो स्थितियां हैं जिनके तहत यह किसी भी "उचित" तरीके से काम करती है।

  1. मैक्रो में रिटर्न स्टेटमेंट नहीं है। आप do while चाल का उपयोग कर सकते हैं।

    #define macro(x) do { int y = x; func(&y); } while (0) 
    
  2. आप केवल जीसीसी को लक्षित करते हैं।

    #define min(x,y) ({ int _x = (x), _y = (y); _x < _y ? _x : _y; }) 
    

अगर आप स्पष्टीकरण दें कि आप मैक्रो का उपयोग करने के लिए है यह मदद मिलेगी (अपने कार्यालय "मैक्रो सोमवार" या कुछ और है?)। अन्यथा हम वास्तव में मदद नहीं कर सकते हैं।

6

सी मैक्रोज़ केवल (अपेक्षाकृत सरल) टेक्स्टुअल प्रतिस्थापन हैं।

तो सवाल जो आप शायद पूछ रहे हैं वह है: क्या मैं नीचे दिए गए उदाहरण में एक फ़ंक्शन में ब्लॉक (यौगिक कथन भी कहा जाता है) बना सकता हूं?

void foo(void) 
{ 
    int a = 42; 
    { 
     int b = 42; 
     { 
      int c = 42; 
     } 
    } 
} 

और उत्तर हाँ है।

अब @DietrichEpp अपने जवाब में यह उल्लेख किया है, यदि मैक्रो अपने उदाहरण की तरह एक यौगिक बयान है, यह do { ... } while (0) बजाय { ... } साथ मैक्रो बयान संलग्न करने के लिए एक अच्छा अभ्यास है के रूप में। नीचे दिए गए लिंक क्या स्थिति एक मैक्रो की कोशिश करता में do { ... } while (0) को रोकने के लिए बताते हैं:

http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html

इसके अलावा

जब आप लिखते हैं एक समारोह की तरह मैक्रो हमेशा अपने आप से पूछना आप ऐसा करने की वजह से सबसे अधिक बार एक लिखने की कोई वास्तविक लाभ है, तो इसके बजाय समारोह बेहतर है।

0

हां यह काम करना चाहिए क्योंकि आप ब्लॉक संरचना का उपयोग करते हैं और अस्थायी चर इस ब्लॉक के आंतरिक दायरे में घोषित किए जाते हैं।

नोट करें कि आखिरी \}} अनावश्यक है।

0

वे कर सकते हैं। उन्हें अक्सर नहीं करना चाहिए।

इस फ़ंक्शन को मैक्रो क्यों होना चाहिए? क्या आप इसे इसके बजाय रेखांकित कर सकते हैं?

+1

छोड़कर आप पाएंगे कि आपका प्रोग्राम बढ़ता है और मुद्दों का समर्थन करता है, मैक्रोज़ द्वारा उत्पन्न कोड को बनाए रखना कम त्रुटि प्रवण नहीं है। यह एक गड़बड़ है। – Marvo

0

यदि आप सी ++ उपयोग इनलाइन का उपयोग कर रहे हैं, या gcc के साथ -o3 का उपयोग करते हैं तो यह आपके लिए सभी कार्यों को रेखांकित करेगा। मुझे अभी भी समझ में नहीं आता है कि आपको इस फ़ंक्शन को मैक्रोराइज़ करने की आवश्यकता क्यों है।

+1

सी में भी 'इनलाइन' है। –

5

यह ज्यादातर ठीक है, सिवाय इसके कि मैक्रो आमतौर पर do { ... } while(0) साथ संलग्न हैं (स्पष्टीकरण के लिए this question पर एक नज़र डालें):

#define ALLOC_FOO(f, size) \ 
    do { \ 
     long  i1, i2;\ 
     double *data[7];\ 
     /* do something */ \ 
    } while(0) 

इसके अलावा, जहाँ तक अपने मूल fooAlloc फ़ंक्शन के रूप में long आप अपनी बदलना होगा किसी भी तरह किसी और परिणाम स्टोर करने के लिए मैक्रो।

#define ALLOC_FOO(f, size) \ 
    ({ \ 
     long  i1, i2;\ 
     double *data[7];\ 
     /* do something */ \ 
     result; \ 
    }) 

अंत में आप मैक्रो तर्क के विस्तार की संभावित दुष्प्रभावों का ध्यान देना चाहिए: या, यदि आप जीसीसी उपयोग करते हैं, आप compound statement विस्तार की कोशिश कर सकते हैं। सामान्य पैटर्न एक ब्लॉक के अंदर प्रत्येक तर्क के लिए एक अस्थायी चर को परिभाषित करने और उन्हें बजाय उपयोग कर रहा है:

#define ALLOC_FOO(f, size) \ 
    ({ \ 
     typeof(f) __f = (f);\ 
     typeof(size) __size = (size);\ 
     long  i1, i2;\ 
     double *data[7];\ 
     /* do something */ \ 
     result; \ 
    }) 
+0

मेरी आंखें खून बह रही हैं – paulm

2

Eldar के जवाब से पता चलता आप मैक्रो प्रोग्रामिंग और कुछ उपयोगी (लेकिन गैर मानक) जीसीसी विस्तार के नुकसान के सबसे।

आप मानक से चिपक चाहते हैं, मैक्रो (genericity के लिए) और inline कार्य (स्थानीय चर के लिए) का एक संयोजन उपयोगी हो सकता है।

inline 
long fooAlloc(void *f, size_t size) 
{ 
    size_t  i1, i2; 
    double *data[7]; 

    /* do something */ 
    return 42; 
} 


#define ALLOC_FOO(T) fooAlloc(malloc(sizeof(T)), sizeof(T)) 

तरह के एक मामले sizeof का उपयोग कर में केवल संकलन समय पर और अपने मूल्य के लिए नहीं प्रकार के लिए अभिव्यक्ति का मूल्यांकन करता है, तो यह दो बार F का मूल्यांकन नहीं होता।

बीटीडब्ल्यू, "आकार" आमतौर पर size_t के साथ टाइप किया जाना चाहिए और long या इसी तरह के साथ नहीं होना चाहिए।

संपादित करें: जोनाथन के सवाल का रूप inline के बारे में काम करता है, मैं C99, here की inline मॉडल के बारे में कुछ लिखा है।

+0

क्या यह 'स्थिर इनलाइन ...' होना चाहिए? –

+0

@ जोनाथन, वह क्यों होगा? –

+0

आपको सी (आईएमओ) में 'इनलाइन' के साथ बेहद सावधान रहना होगा। एसओ पर मिले तीन सबसे प्रासंगिक प्रश्न हैं ["इनलाइन परिभाषाएं?"] (Http://stackoverflow.com/questions/8454690/inline-definitions), ["सी 99 में स्थिर या बाहरी कभी भी उपयोगी नहीं है?" ] (http://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99), और ["बाहरी इनलाइन?"] (http: // stackoverflow। कॉम/प्रश्न/216510/बाहरी-इनलाइन), किसी भी विशेष क्रम में नहीं। (और, रिकॉर्ड के लिए, मैं इस मुद्दे पर प्रभाव नहीं डाल रहा हूं; मैं एक प्रश्न पूछ रहा था।) –

7

सबसे पहले, मैं दृढ़ता से इनलाइन कार्यों सलाह देते हैं। वहाँ बहुत कुछ चीजें मैक्रो कर सकते हैं और कर रहे हैं वे नहीं कर सकते हैं, और वे भी बहुत कुछ आप क्या उम्मीद करते हैं की संभावना हो।

मैक्रोज़ का एक पतन, जिसे मैंने अन्य उत्तरों में नहीं देखा, परिवर्तनीय नामों की छायांकन कर रहा है।

int temp = 3; 
A(temp); 

पूर्व प्रसंस्करण के बाद, कोड है::

#define A(x) { int temp = x*2; printf("%d\n", temp); } 

और अगर कोई इसे इस तरह इस्तेमाल किया:
आप परिभाषित मान लीजिए,

int temp = 3; 
{ int temp = temp*2; printf("%d\n", temp); } 

यह काम नहीं करता क्योंकि आंतरिक अस्थायी बाहरी छाया।
आम समाधान, चर __temp कॉल करने के लिए है कोई भी यह सोचते हैं एक चर इस नाम का प्रयोग (जो एक अजीब धारणा है, यह देखते हुए कि तुम सिर्फ यह किया) को परिभाषित करेगा।

0

एक परिपूर्ण नहीं समाधान: (पुनरावर्ती मैक्रो के साथ काम नहीं करता है, उदाहरण के लिए एक दूसरे के अंदर कई छोरों)

#define JOIN_(X,Y) X##Y 
#define JOIN(X,Y) JOIN_(X,Y) 
#define TMP JOIN(tmp,__LINE__) 

#define switch(x,y) int TMP = x; x=y;y=TMP 

int main(){ 
    int x = 5,y=6; 
    switch(x,y); 
    switch(x,y); 
} 

बन जाएगा पूर्वप्रक्रमक चलाने के बाद:

int main(){ 
    int x=5,y=6; 
    int tmp9 = x; x=y; y=tmp9; 
    int tmp10 = x; x=y; y=tmp10; 
} 
संबंधित मुद्दे