इनलाइन फ़ंक्शंस बनाम प्रीप्रोसेसर मैक्रोज़


जवाबों:


127

प्रीप्रोसेसर मैक्रोज़ आपके कोड पर लागू होने वाले प्रतिस्थापन पैटर्न हैं। उन्हें आपके कोड में लगभग कहीं भी उपयोग किया जा सकता है क्योंकि किसी भी संकलन के शुरू होने से पहले उन्हें उनके विस्तार के साथ बदल दिया जाता है।

इनलाइन फ़ंक्शन वास्तविक फ़ंक्शन हैं जिनके शरीर को सीधे उनकी कॉल साइट में इंजेक्ट किया जाता है। उनका उपयोग केवल वहां किया जा सकता है जहां फ़ंक्शन कॉल उपयुक्त है।

अब, जहाँ तक फ़ंक्शन-जैसे संदर्भ में मैक्रोज़ बनाम इनलाइन फ़ंक्शंस का उपयोग करने की सलाह दी जाती है:

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

39
इनलाइन फ़ंक्शन को हमेशा इनलाइन होने की गारंटी नहीं दी जाती है: क्योंकि कंपाइलर इनलाइन नहीं करेगा यदि ऐसा करने से धीमी कोड आदि उत्पन्न होगा। कंपाइलर बहुत विश्लेषण करता है जो कि इंजीनियर नहीं कर सकता है और सही काम करता है।
मार्टिन

14
मेरा मानना ​​है कि पुनरावर्ती कार्य एक और उदाहरण है जहां अधिकांश संकलक इनलाइनिंग की उपेक्षा करते हैं।

क्या इस मामले में C ++ की तुलना में C में कोई महत्वपूर्ण अंतर हैं?
rzetterberg

7
एक बिंदु का उल्लेख नहीं किया गया है कि संकलन झंडों से प्रभावित हो सकता है। उदाहरण के लिए, जब आप अधिकतम गति के लिए बनाते हैं (जैसे GCC -O2 / -O3) कंपाइलर कई कार्यों को इनलाइन करेगा, लेकिन जब आप न्यूनतम आकार (-ओ) के लिए निर्माण करेंगे तो आमतौर पर इनलाइन फ़ंक्शंस केवल एक बार (या बहुत छोटे फ़ंक्शंस) )। मैक्रोज़ के साथ ऐसा कोई विकल्प नहीं है।
dbrank0

मैक्रो पहुँच विवरण के साथ कवर नहीं कर सकता (जैसे, निजी या संरक्षित) जबकि इनलाइन फ़ंक्शन संभव हैं।
हिट की

78

सबसे पहले, प्रीप्रोसेसर मैक्रोज़ संकलन से पहले कोड में "कॉपी पेस्ट" हैं। तो कोई प्रकार की जाँच नहीं है , और कुछ दुष्प्रभाव दिखाई दे सकते हैं

उदाहरण के लिए, यदि आप 2 मानों की तुलना करना चाहते हैं:

#define max(a,b) ((a<b)?b:a)

साइड इफेक्ट दिखाई देते हैं यदि आप max(a++,b++)उदाहरण के लिए उपयोग करते हैं ( aया bदो बार वृद्धि की जाएगी)। इसके बजाय, उपयोग करें (उदाहरण के लिए)

inline int max( int a, int b) { return ((a<b)?b:a); }

3
बस अपने उदाहरण में जोड़ना चाहते हैं कि साइड इफेक्ट के अलावा, मैक्रो अतिरिक्त कार्य भार भी पेश कर सकता है, विचार करें max(fibonacci(100), factorial(10000))कि बड़े को दो बार गणना की जाएगी :(
वॉटरशुन

हर कोई टाइप चेकिंग के बारे में बोलता है, लेकिन सिर्फ आपने एक वास्तविक दुनिया का उदाहरण दिया है, इसीलिए मैं इस जवाब को बढ़ाता हूं।
इवानजिनो

16

इनलाइन फ़ंक्शन को कंपाइलर द्वारा विस्तारित किया जाता है, जहां मैक्रोज़ प्रीप्रोसेसर द्वारा विस्तारित होते हैं, जो कि केवल पाठीय प्रतिस्थापन है। हेंस

  • मैक्रो इनवोकेशन के दौरान कोई प्रकार की जाँच नहीं है, जबकि फ़ंक्शन कॉल के दौरान टाइप जाँच की जाती है।

  • तर्कों के पुनर्मूल्यांकन और संचालन के क्रम के कारण वृहद विस्तार के दौरान अवांछित परिणाम और अक्षमता हो सकती है। उदाहरण के लिए

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);

    में परिणाम होगा

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
  • स्थूल विस्तार से पहले स्थूल तर्कों का मूल्यांकन नहीं किया जाता है

    #define MUL(a, b) a*b
    int main()
    {
      // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
      printf("%d", MUL(2+3, 3+5));
     return 0;
    }
    // Output: 16`
  • फ़ंक्शन के मामले में मान वापस करने के लिए मैक्रो में रिटर्न कीवर्ड का उपयोग नहीं किया जा सकता है।

  • इनलाइन कार्यों को ओवरलोड किया जा सकता है

  • मैक्रों को दिए गए टोकन को ऑपरेटर ## का उपयोग करके सुधारा जा सकता है जिसे टोकन-पेस्टिंग ऑपरेटर कहा जाता है।

  • मैक्रोज़ आमतौर पर कोड के पुन: उपयोग के लिए उपयोग किया जाता है जहां फ़ंक्शन कॉल के दौरान इनलाइन फ़ंक्शन (अतिरिक्त समय) को समाप्त करने के लिए इनलाइन फ़ंक्शन का उपयोग किया जाता है (एक सबरूटीन पर कूदने से बचना)।


13

मुख्य अंतर प्रकार की जाँच है। कंपाइलर यह जांच करेगा कि आप इनपुट मानों के रूप में क्या पास करते हैं, यह उस प्रकार का है जिसे फ़ंक्शन में पास किया जा सकता है। प्रीप्रोसेसर मैक्रोज़ के साथ यह सच नहीं है - वे किसी भी प्रकार की जाँच से पहले विस्तारित होते हैं और इससे बग का पता लगाने में गंभीर और मुश्किल हो सकती है।

यहाँ कई अन्य कम स्पष्ट बिंदु उल्लिखित हैं।


11

पहले से दिए गए लोगों के लिए एक और अंतर जोड़ने के लिए: आप #defineडीबगर में एक के माध्यम से कदम नहीं रख सकते हैं , लेकिन आप इनलाइन फ़ंक्शन के माध्यम से कदम रख सकते हैं।



3

इनलाइन फ़ंक्शन मैक्रोज़ के समान हैं (क्योंकि संकलन समय पर कॉल के बिंदु पर फ़ंक्शन कोड का विस्तार होता है), इनलाइन फ़ंक्शन कंपाइलर द्वारा पार्स किए जाते हैं, जबकि मैक्रोज़ प्रीप्रोसेसर द्वारा विस्तारित होते हैं। परिणामस्वरूप, कई महत्वपूर्ण अंतर हैं:

  • इनलाइन फ़ंक्शन सामान्य कार्यों पर लागू प्रकार की सुरक्षा के सभी प्रोटोकॉल का पालन करते हैं।
  • इनलाइन फ़ंक्शन किसी अन्य फ़ंक्शन के समान सिंटैक्स का उपयोग करके निर्दिष्ट किए जाते हैं, सिवाय इसके कि वे फ़ंक्शन घोषणा में इनलाइन कीवर्ड शामिल करते हैं।
  • इनलाइन कार्यों के तर्क के रूप में व्यक्त अभिव्यक्तियों का मूल्यांकन एक बार किया जाता है।
  • कुछ मामलों में, मैक्रोज़ के तर्क के रूप में पारित किए गए अभिव्यक्तियों का एक से अधिक बार मूल्यांकन किया जा सकता है। http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • मैक्रो पूर्व-संकलित समय पर विस्तारित होते हैं, आप उन्हें डीबगिंग के लिए उपयोग नहीं कर सकते हैं, लेकिन आप इनलाइन फ़ंक्शन का उपयोग कर सकते हैं।

- अच्छा लेख : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;


2

एक इनलाइन फ़ंक्शन वैल्यू सिमेंटिक्स बनाए रखेगा, जबकि एक प्रीप्रोसेसर मैक्रो सिंटैक्स को कॉपी करता है। यदि आप कई बार तर्क का उपयोग करते हैं, तो आप प्रीप्रोसेसर मैक्रो के साथ बहुत सूक्ष्म कीड़े प्राप्त कर सकते हैं - उदाहरण के लिए यदि तर्क में "i ++" जैसे उत्परिवर्तन होता है, जो दो बार निष्पादित होता है तो काफी आश्चर्य होता है। इनलाइन फ़ंक्शन से यह समस्या नहीं होगी।


1

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


1

मैक्रो और इनलाइन फ़ंक्शन के बीच अंतर जानने के लिए , सबसे पहले हमें यह जानना चाहिए कि वे वास्तव में क्या हैं और हमें उनका उपयोग कब करना चाहिए।

समारोह :

int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • फंक्शन कॉल्स में इसके साथ ओवरहेड जुड़ा होता है, क्योंकि फंक्शन खत्म होने के बाद इसे पता करना होता है कि इसे कहां लौटना है और स्टैक मेमोरी में वैल्यू स्टोर करने की भी जरूरत है।

  • छोटे अनुप्रयोगों के लिए यह एक समस्या नहीं होगी, लेकिन चलो उन वित्तीय अनुप्रयोगों का एक उदाहरण लेते हैं जहां हर सेकंड हजारों लेनदेन हो रहे हैं, हम फ़ंक्शन कॉल के साथ नहीं जा सकते हैं।

मैक्रो:

# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • मैक्रोज़ प्रीप्रोसेसिंग स्टेज पर काम करता है यानी इस स्तर पर # कीवर्ड के साथ लिखे गए स्टेटमेंट को कंटेंट से बदल दिया जाएगा

int परिणाम = वर्ग (x * x)

लेकिन मैक्रोज़ के पास इससे जुड़े कीड़े हैं।

#define Square(x) x*x
int main() {
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

यहां आउटपुट 11 नहीं 36 है

ऑनलाइन समारोह :

inline int Square(int x) {
    return x * x;
}

int main() {
    using namespace std;
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

आउटपुट 36

इनलाइन कीवर्ड फ़ंक्शन को फ़ंक्शन के शरीर के साथ फ़ंक्शन कॉल को बदलने के लिए कंपाइलर का अनुरोध करता है, यहां आउटपुट सही है क्योंकि यह पहले अभिव्यक्ति का मूल्यांकन करता है और फिर पारित हो जाता है। यह फ़ंक्शन कॉल को ओवरहेड को कम कर देता है क्योंकि रिटर्न एड्रेस और स्टैक को स्टोर करने की कोई आवश्यकता नहीं है। फ़ंक्शन तर्कों के लिए मेमोरी की आवश्यकता नहीं है।

मैक्रोज़ और इनलाइन कार्यों के बीच तुलना:

  1. मैक्रोज़ प्रतिस्थापन के माध्यम से काम करता है, जबकि इनलाइन फ़ंक्शंस में, फ़ंक्शन कॉल को शरीर के साथ बदल दिया जाता है।
  2. मैक्रो प्रतिस्थापन के कारण त्रुटि प्रवण हैं जबकि इनलाइन फ़ंक्शन उपयोग करने के लिए सुरक्षित हैं।
  3. मैक्रोज़ का पता नहीं है जबकि इनलाइन फ़ंक्शन का पता है।
  4. मैक्रोज़ को कोड की कई लाइनों के साथ उपयोग करना मुश्किल है, जबकि इनलाइन फ़ंक्शन नहीं हैं।
  5. C ++ मैक्रोज़ में सदस्य फ़ंक्शन के साथ उपयोग नहीं किया जा सकता है जबकि इनलाइन फ़ंक्शन हो सकता है।

निष्कर्ष:

इनलाइन फ़ंक्शन कभी-कभी मैक्रोज़ की तुलना में अधिक उपयोगी होते हैं, क्योंकि यह प्रदर्शन में सुधार करता है और उपयोग करने के लिए सुरक्षित है और फ़ंक्शन कॉल को भी कम कर देता है। यह संकलक से केवल एक अनुरोध है, कुछ कार्यों को इनलाइन नहीं किया जाएगा:

  • बड़े कार्य
  • कई सशर्त तर्क वाले कार्य
  • पुनरावर्ती कोड और कोड के साथ छोरों आदि।

जो एक अच्छी बात है, क्योंकि जब भी कंपाइलर सोचता है कि चीजों को दूसरे तरीके से करना सबसे अच्छा है।


केवल एक टिप्पणी के रूप में: मैक्रो को कोष्ठक के साथ एक ही नंबर पर मूल्यांकन करने के लिए तय किया जा सकता है। हालांकि, यह अभी भी त्रुटि प्रवण है, क्योंकि आपको कार्यान्वयन के दौरान पूर्ण गूंगा निर्वाह और सभी मामलों के बारे में सोचने की आवश्यकता है।
माइक

0

जीसीसी में (मुझे दूसरों के बारे में निश्चित नहीं है), एक फ़ंक्शन इनलाइन की घोषणा करना, संकलक के लिए एक संकेत है। यह अभी भी दिन के अंत में कंपाइलर पर निर्भर करता है कि वह यह तय करे कि जब भी इसे कहा जाए, तो यह फंक्शन की बॉडी में शामिल है या नहीं।

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

#define MACRO_FUNC(X) ...

जहां MACRO_FUNC स्पष्ट रूप से फ़ंक्शन के शरीर को परिभाषित करता है। विशेष देखभाल की आवश्यकता है ताकि यह सही ढंग से चलता रहे सभी मामलों में एक फ़ंक्शन का उपयोग किया जा सकता है, उदाहरण के लिए एक खराब लिखित MACRO_FUNC एक त्रुटि का कारण होगा

if(MACRO_FUNC(y)) {
 ...body
}

एक सामान्य फ़ंक्शन का उपयोग वहां किसी समस्या के साथ नहीं किया जा सकता है।


0

कोडिंग के दृष्टिकोण से, एक इनलाइन फ़ंक्शन एक फ़ंक्शन की तरह है। इस प्रकार, एक इनलाइन फ़ंक्शन और मैक्रो के बीच अंतर एक फ़ंक्शन और मैक्रो के बीच अंतर के समान है।

संकलन के दृष्टिकोण से, एक इनलाइन फ़ंक्शन एक मैक्रो के समान है। इसे सीधे कोड में इंजेक्ट किया जाता है, जिसे कॉल नहीं किया जाता है।

सामान्य तौर पर, आपको इनलाइन फ़ंक्शंस पर विचार करना चाहिए, जिसमें कुछ छोटे ऑप्टिमाइज़ेशन के साथ नियमित फ़ंक्शंस शामिल हैं। और अधिकांश ऑप्टिमाइज़ेशन की तरह, यह कंपाइलर पर निर्भर करता है कि वह यह तय करे कि क्या वास्तव में इसे लागू करना है। अक्सर कंपाइलर विभिन्न कारणों से प्रोग्रामर को इनलाइन करने के किसी भी प्रयास को खुशी से अनदेखा कर देगा।


0

इनलाइन फ़ंक्शन एक फ़ंक्शन कॉल के रूप में व्यवहार करेंगे यदि इसमें कोई पुनरावृत्ति या पुनरावर्ती कथन मौजूद है, ताकि निर्देशों के बार-बार निष्पादन को रोका जा सके। यह आपके प्रोग्राम की समग्र मेमोरी को बचाने में काफी मददगार है।


-1
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{ 
    return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases. 
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
 return a*a*a;
}
int main()
{
 cout<<NUMBER<<endl<<number()<<endl;
 cout<<CUBE(1+3); //Unexpected output 10
 cout<<endl<<cube(1+3);// As expected 64
 return 0;
}

मैक्रो आमतौर पर फ़ंक्शंस से अधिक तेज़ होते हैं क्योंकि उनमें वास्तविक फ़ंक्शन कॉल ओवरहेड शामिल नहीं होता है।

मैक्रोज़ के कुछ नुकसान: कोई प्रकार की जाँच नहीं है। डीबग करने के लिए पर्याप्त है क्योंकि वे सरल प्रतिस्थापन का कारण बनते हैं। मैक्रो में नाम स्थान नहीं है, इसलिए कोड के एक खंड में एक मैक्रो अन्य अनुभाग को प्रभावित कर सकता है। क्यूआरबीई () उदाहरण के ऊपर मैक्रोज़ साइड इफेक्ट्स का कारण बन सकते हैं।

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


आपको #define TWO_N(n) 2 << nऔर फिर कितना मज़ा आता है cout << CUBE(TWO_N(3 + 1)) << endl;? (इसके साथ endlउन्हें शुरू करने की तुलना में आउटपुट की लाइनों को समाप्त करना बेहतर है ।)
जोनाथन लेफ़लर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.