C ++ में इनलाइन फ़ंक्शन। क्या बात है?


19

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


जवाबों:


40

inlineसी से है; यह C ++ के लिए नया नहीं था।

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

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


3
के इतिहास के लिए +1 inline
तमारा विज्समैन

11
मुझे पूरा यकीन है कि inlineइसे C ++ में मानकीकृत किया गया था, हालांकि यह पहले से ही सी में विक्रेता के विस्तार के रूप में उपलब्ध था। हां, ऐसा लगता है कि इसे C99 में C मानक में जोड़ा गया था।
बेन वोइगट

@ बॉन वायगेट: आप सही कह रहे हैं। मैंने पहली बार इसका सामना किया
डेविड थोरले

5
यह भी ध्यान रखें कि न केवल इतिहास गलत है, बल्कि inlineC99 के नियम और बाद inlineमें C ++ के नियमों से भिन्न हैं ।
अल्फ पी। स्टेनबाक

27

मूल रूप inlineसे एक बहुत ही मजबूत संकेत था कि फ़ंक्शन को कॉल करना चाहिए।

लेकिन इसका एकमात्र गारंटीकृत प्रभाव inlineकई अनुवाद इकाइयों में किसी फ़ंक्शन को परिभाषित करने (प्रभावी रूप से पहचानने) की अनुमति देना है, उदाहरण के लिए, आप परिभाषा को हेडर फ़ाइल में रखते हैं।

आजकल, कुछ संकलक इनलाइनिंग संकेत, जैसे जी ++ के बाद बहुत उत्सुक हैं। और कुछ संकलक इसे कम गंभीरता से लेते हैं, जैसे विज़ुअल सी ++। लेकिन सभी को गारंटी का पालन करना होगा।

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

यह भी दुर्भाग्यपूर्ण है कि inline(या बेहतर, त्यागने योग्य परिभाषा के बारे में एक अलग कीवर्ड) डेटा पर लागू नहीं किया जा सकता है ।

लिंकर के स्तर को त्यागने योग्य डेटा की आवश्यकता बढ़ गई है क्योंकि हेडर-केवल मॉड्यूल अधिक लोकप्रिय हो गए हैं। जैसे, कई बूस्ट सब-लाइब्रेरी हेडर-ओनली हैं।

हालाँकि, डेटा के लिए, आप टेम्प्लेट के साथ थोड़ा ट्रिक लगा सकते हैं। इसे कुछ वर्ग टेम्पलेट में परिभाषित करें, typedefटेम्पलेट पैरामीटर void(या जो भी) के साथ प्रदान करें । ऐसा इसलिए है क्योंकि एक परिभाषा नियम टेम्पलेट्स के लिए एक विशिष्ट अपवाद बनाता है।

नोट:
¹ inlineचर C ++ 17 में समर्थित होंगे ।


1
के बारे में अतिरिक्त जानकारी के लिए +1 inline
तमारा विज्समैन

1
" प्रभावी रूप से पहचान " वास्तव में एक बहुत ही मुश्किल स्थिति है, क्योंकि बहुत बुरी तरह से डिज़ाइन की गई C ++ भाषाएं सामान्य रूप से सक्षम बनाने के लिए बहुत कोशिश करती हैं और सावधान प्रोग्रामर उचित लेकिन औपचारिक रूप से अपरिभाषित कोड लिखते हैं जो स्थैतिक वस्तुओं का उपयोग करता है - मुझे आश्चर्य है कि कितने कमेटी मेंबर खुद फंदे में पड़ जाते हैं
जिज्ञासु

6

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


5
लेकिन कंपाइलर सामान्य रूप से प्रोग्रामर की तुलना में इसे बेहतर कर सकता है (और करता है)। तो यह एक मान्य तर्क नहीं है।
कोनराड रूडोल्फ

" हर फ़ंक्शन कॉल को अब फ़ंक्शन के पूर्ण कोड के साथ प्रतिस्थापित किया जाना चाहिए " और इनलाइन फ़ंक्शन एक फ़ंक्शन नहीं है जहां कॉल अनुक्रम छोड़ा गया है और जहां फ़ंक्शन के असेंबली कोड को जगह में कॉपी किया गया है। उच्च स्तर के मध्यवर्ती कोड इनलाइन को लाकर एक इनलाइन फ़ंक्शन संकलित किया जाता है। यह संकलक को फ़ंक्शन बॉडी को प्रभावी रूप से एक स्वच्छ मैक्रो के रूप में प्रभावी ढंग से व्यवहार करने की अनुमति देता है (एक स्वच्छ मैक्रो वह है जिसमें सी प्रीप्रोसेसर मैक्रोज़ की quirks नहीं है), संभावित रूप से कई अनुकूलन उपलब्ध हैं।
जिज्ञासु

3

"इनलाइन" को समझने के लिए आपको इतिहास को समझने की जरूरत है और 20 साल पहले (और 30) की तरह जीवन क्या था।

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

इसलिए प्रत्येक कोड फ़ाइल को अलग से एक ऑब्जेक्ट फ़ाइलों में संकलित किया गया था। प्रत्येक ऑब्जेक्ट फ़ाइल फ़ंक्शन के "पते" के साथ, सभी फ़ंक्शन की सूची के साथ शुरू हुई। ऑब्जेक्ट फ़ाइल में कॉल के स्थान के साथ अन्य ऑब्जेक्ट फ़ाइलों में कॉल किए जाने वाले सभी कार्यों की एक सूची भी थी।

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

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

कंपाइलर ने कभी भी कोड को ".c" या ".cpp" फ़ाइल में देखा था, यह सभी शामिल हेडर फ़ाइलों के साथ संकलन कर रहा था। इसलिए यह अन्य ".c" या ".cpp" फ़ाइलों में कोड के आधार पर कोई अनुकूलन नहीं कर सका।

"इनलाइन" कीवर्ड ने एक फ़ंक्शन (विधि) के शरीर को हेडर फ़ाइल में परिभाषित किया जा सकता है, इसलिए संकलक को कोड का संकलन करते समय फ़ंक्शन के कोड का उपयोग करने की अनुमति देता है। उदाहरण के लिए, आपके पास ather .cpp फ़ाइल में एक संग्रह वर्ग परिभाषित था, इस वर्ग में एक "isEmpty" विधि होगी, जिसमें कोड की एक पंक्ति होती थी, यदि किसी फ़ंक्शन के बजाय कॉल के बजाय परिणामी प्रोग्राम का एक बड़ा स्पीडअप होगा। फ़ंक्शन कॉल को इस एक पंक्ति के साथ बदल दिया गया था।

"इनलाइन" कीवर्ड को उस समय फ़ंक्शन कॉल की लागत से बचने के लिए डेटा के इनकैप्सुलेशन की अनुमति देने के लिए एक "सस्ते और आसान" तरीके के रूप में देखा गया था, इसके बिना बहुत सारे प्रोग्रामर ऑब्जेक्ट के निजी क्षेत्रों तक पहुंच पाएंगे। (मैक्रोस जहां एक बहुत बुरा तरीका "inlining" कोड है, जहां उस समय आम है।)

इन दिनों "लिंकर्स" बहुत सारे कोड ऑप्टिमाइज़ेशन करते हैं और कुछ टीम द्वारा कंपाइलर के रूप में लिखे जाते हैं। कंपाइलर अक्सर चेक करता है कि कोड सही है और इसे "कंप्रेस" करता है, जिससे मशीन कोड निर्माण का अधिकांश काम लिंकर पर चला जाता है।


2

आइए देखें कि मानक क्या कहता है (बोल्ड में महत्वपूर्ण भागों पर प्रकाश डाला गया):

2. एक इनलाइन विनिर्देशक के साथ एक फ़ंक्शन घोषणा एक इनलाइन फ़ंक्शन को घोषित करता है। इनलाइन स्पेसियर कार्यान्वयन को इंगित करता है कि कॉल के बिंदु पर फ़ंक्शन बॉडी के इनलाइन प्रतिस्थापन को सामान्य चेकिंग तंत्र के लिए प्राथमिकता दी जानी है। कॉल के बिंदु पर इस इनलाइन प्रतिस्थापन को निष्पादित करने के लिए कार्यान्वयन की आवश्यकता नहीं है ; हालाँकि, भले ही इस इनलाइन प्रतिस्थापन को छोड़ दिया गया हो, इनलाइन फ़ंक्शंस के लिए अन्य नियमों का अभी भी सम्मान किया जाएगा।

- सी ++ मानक, आईएसओ / आईईसी 14882: 2003 , 7.1.2 फ़ंक्शन विनिर्देशक [dcl.fct.spec]

इसलिए, यदि आप सुनिश्चित होना चाहते हैं, तो आपको अपने संकलक के प्रलेखन को पढ़ना चाहिए।

सब कुछ सम्मिलित करना एक बुरा विचार है, क्योंकि इसके परिणामस्वरूप बहुत सारे डुप्लिकेट किए गए मशीन कोड हो सकते हैं ...

तो आपको जानना होगा:

कोई सरल उत्तर नहीं हैं: आपको यह देखने के लिए खेलना होगा कि सबसे अच्छा क्या है। करो नहीं की तरह, "कभी भी उपयोग साधारण जवाब के लिए समझौता inlineकार्यों" या "हमेशा उपयोग inlineकार्यों" या "का प्रयोग करें inlineकार्यों समारोह कोड के एन लाइनों से भी कम है यदि और केवल यदि।" इन एक-आकार-फिट-सभी नियमों को लिखना आसान हो सकता है, लेकिन वे उप-इष्टतम परिणाम पैदा करेंगे।

- C ++ FAQ, Inline Functions , 9.3 क्या inlineकार्य प्रदर्शन में सुधार करते हैं?


1
आप जो कहते हैं वह सच है, लेकिन प्रासंगिक नहीं है क्योंकि प्रोग्रामर के रूप में यह आपका निर्णय नहीं है कि इनलाइन है या नहीं। आप कीवर्ड डालते हैं, आप अपने कार्यों को इनबिल्ट कर सकते हैं या नहीं कर सकते हैं। आप कीवर्ड नहीं डालते हैं, आप अभी भी उन्हें प्राप्त कर सकते हैं या नहीं कर सकते हैं। जब आप कीवर्ड डालते हैं, तो ऐसा कोई भी नियम नहीं होता है कि कंपाइलर वास्तव में निर्णय लेने वाला हो।
केट ग्रेगोरी

यह कैसे प्रासंगिक नहीं है अगर यह आपके जैसा ही कहता है? कोई सरल उत्तर नहीं हैं
तमारा विज्समैन

यह प्रासंगिक नहीं है क्योंकि यह OPs प्रश्न का उत्तर नहीं देता है। वह "इनलाइन क्या करता है" नहीं पूछ रहा है, वह "व्हाट्स द पॉइंट" पूछ रहा है। और आपका जवाब सिर्फ वही बताता है जो हम सभी इनलाइन के बारे में पहले से जानते हैं।
द्रालो

@Davor: "क्या बात है?" एफएक्यू का पालन नहीं करता है, इसलिए मैं सवालों के जवाब दे रहा हूं। मैं inlineज्ञान को दोहराते हुए बिंदु को बता रहा हूं क्योंकि ओपी को एक हिस्सा याद आ रहा है, जो मुख्य कारण है कि वह बिंदु क्यों नहीं प्राप्त करता है। एक बिंदु प्राप्त करने के लिए उसे उस बिंदु के नीचे क्या है की समझ
होनी चाहिए

नरक यह अक्सर पूछे जाने वाले प्रश्न का पालन क्यों नहीं करेगा? मानक इनलाइन कीवर्ड के सिंटैक्स और शब्दार्थों का वर्णन करता है, और ओपीएस सवाल यह है कि उद्देश्य क्या है, इसका उपयोग कब किया जाना चाहिए, इसे हल करने के लिए क्या समस्याएं हैं? मैं यह नहीं देखता कि कैसे अक्सर पूछे जाने वाले प्रश्न का पालन नहीं होता है।
--द्रालो

1

मुझे इनलाइन कीवर्ड का उपयोग करने का एक अच्छा कारण दें।

एक एम्बेडेड सिस्टम पर, जैसे कि टिकट प्रिंटर या इसी तरह की छोटी प्रणाली। प्रोसेसर बहुत ही सीमित है और एक फंक्शन कॉल (स्टैक पर फंक्शन पैरामीटर तैयार करना, स्टैक से पैरामिक्स, बैक आंसर आदि डालना है)) फंक्शन के बगल में, निष्पादित करने के लिए कई एमएस ले सकता है।

कहते हैं कि कॉल का समय लगभग 60ms है (केवल कॉल करने के लिए, वास्तविक कार्य नहीं) और आपने 50 पुनरावृत्तियों (एक पेड़ में लूप या पुनरावृति कॉल) किए हैं।

उस फ़ंक्शन कॉल से बस आगे और पीछे जाने का समय 60 * 50 = 3000 (3 सेकंड) होगा।

यदि आपके पास मेमोरी है तो आप निश्चित रूप से 3 सेकंड बचाने के लिए इनलाइन करेंगे।

तो इनलाइन मूल रूप से उपयोग किया जाता है जब आपको निष्पादन की गति की आवश्यकता होती है। कुछ परियोजनाओं में मैं शामिल था, इनलाइन का उपयोग करने के लिए कॉलिंग का समय निष्पादन समय, एक क्लासिक स्थिति से अधिक लंबा था।


एह, क्या? अपने कोड में इनलाइन डालने का मतलब यह नहीं है कि कंपाइलर वास्तव में इसे इनलाइन करेगा, और इसे वहां नहीं डालने का मतलब यह भी नहीं है कि यह अभ्यस्त है। यह सिर्फ एक संकेत है, जिसे आजकल के कंपाइलरों ने नजरअंदाज कर दिया है। यदि संकलक इसे इनलाइन के लिए उपयोगी पाता है, तो यह अभ्यस्त होगा। आपका वहां कोई वास्तविक नियंत्रण नहीं है। ओपी यह पहले से ही जानता है, और पूछ रहा है, मैं बोली: "क्या बात है?"। कौन इस पर +1 देता है? यह दोनों भ्रामक है (उस कीवर्ड इनलाइन को लागू करना लागू करता है) और सवाल के लिए अप्रासंगिक है।
दादरू

2
@ @Dralo अशिष्ट होने की आवश्यकता नहीं है। मैंने प्रश्न की व्याख्या की कि मुझे इनलाइन का उपयोग क्यों करना चाहिए? मेरा कहना यह था कि आप स्मृति की कीमत पर कोड को तेज़ी से प्राप्त कर सकते हैं। प्रत्येक कंपाइलर इनलाइन कीवर्ड को अलग-अलग संभाल सकता है, इसलिए आपको प्रलेखन की जांच करने की आवश्यकता है, जिसका मैंने उल्लेख नहीं किया है। चूँकि आप हमेशा अतिरिक्त मेमोरी ओवरहेड इनलाइन नहीं बना सकते हैं, इसका उपयोग करने के लिए "गाइड" करना उपयोगी है। मैंने यह भी नहीं कहा कि इनलाइन लागू हैं। किसी ने इस उत्तर को उसके / उसके लिए उपयोगी माना और +1 किया, कृपया सम्मान करें कि दूसरे को अनुभव का एक और स्तर मिल सकता है और कुछ उपयोगी मिल सकता है।
मैक्स किंडलैंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.