c++ - लिंक वाले वास्तव में गुणा-परिभाषित `इनलाइन 'फ़ंक्शंस के साथ क्या करते हैं?




linker inline (3)

मुझे लगता है कि आपके प्रश्न का सही उत्तर है "यह निर्भर करता है"

कोड के निम्नलिखित टुकड़े पर विचार करें:

फ़ाइल xc (या x.cc):

#include <stdio.h>

void otherfunction(void);

inline void inlinefunction(void) {
    printf("inline 1\n");
}

int main(void) {
    inlinefunction();
    otherfunction();
    return 0;
}

फ़ाइल yc (या y.cc)

#include <stdio.h>

inline void inlinefunction(void) {
    printf("inline 2\n");
}

void otherfunction(void) {
    printf("otherfunction\n");
    inlinefunction();
}

चूंकि inline कीवर्ड फ़ंक्शन को इनलाइन करने के लिए संकलित करने के लिए केवल एक "सुझाव" है अलग-अलग झंडे वाले अलग-अलग कम्पाइलर अलग तरीके से व्यवहार करते हैं। उदा सी संकलक हमेशा "निर्यात" इनलाइन कार्यों की तरह लग रहा है और कई परिभाषाओं के लिए अनुमति नहीं देता है:

$ gcc x.c y.c && ./a.out 
/tmp/ccy5GYHp.o: In function `inlinefunction':
y.c:(.text+0x0): multiple definition of `inlinefunction'
/tmp/ccQkn7m4.o:x.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

जबकि सी ++ इसे अनुमति देता है:

$ g++ x.cc y.cc && ./a.out 
inline 1
otherfunction
inline 1

अधिक रोचक - चलो फाइलों के ऑर्डर को बदलने का प्रयास करें (और ऐसा - लिंक करने का क्रम स्विच करें):

$ g++ y.cc x.cc && ./a.out 
inline 2
otherfunction
inline 2

अच्छा ... ऐसा लगता है कि पहले एक मायने रखता है! लेकिन ... चलो कुछ अनुकूलन झंडे जोड़ते हैं:

$ g++ y.cc x.cc -O1 && ./a.out 
inline 1
otherfunction
inline 2

और यही वह व्यवहार है जिसे हम उम्मीद करते हैं। फंक्शन को रेखांकित किया गया। फ़ाइलों के अलग-अलग आदेश कुछ भी नहीं बदलेगा:

$ g++ x.cc y.cc -O1 && ./a.out 
inline 1
otherfunction
inline 2

इसके बाद हम अपने एक्ससी (एक्स.के.सी.) स्रोत को किसी अन्य void anotherfunction(void) प्रोटोटाइप के साथ विस्तारित कर सकते हैं और इसे हमारे main फ़ंक्शन में कॉल कर सकते हैं। आइए anotherfunction (z.cc) फ़ाइल में एक और परिभाषा परिभाषित करें:

#include <stdio.h>

void inlinefunction(void);

void anotherfunction(void) {
    printf("anotherfunction\n");
    inlinefunction();
}

हम इस समय inlinefunction के शरीर को परिभाषित नहीं करते हैं। सी ++ के लिए संकलन / निष्पादन निम्नलिखित परिणाम देता है:

$ g++ x.cc y.cc z.cc && ./a.out 
inline 1
otherfunction
inline 1
anotherfunction
inline 1

विभिन्न आदेश:

$ g++ y.cc x.cc z.cc && ./a.out 
inline 2
otherfunction
inline 2
anotherfunction
inline 2

अनुकूलन:

$ g++ x.cc y.cc z.cc -O1 && ./a.out 
/tmp/ccbDnQqX.o: In function `anotherfunction()':
z.cc:(.text+0xf): undefined reference to `inlinefunction()'
collect2: ld returned 1 exit status

तो निष्कर्ष है: सबसे अच्छा inline को static साथ घोषित करना है, जो फ़ंक्शन उपयोग की गुंजाइश को संकुचित करता है, क्योंकि फ़ंक्शन का "निर्यात" करना हम इनलाइन का उपयोग करना चाहते हैं, कोई मतलब नहीं है

सी और सी ++ दोनों में, बाहरी लिंकेज के साथ inline फ़ंक्शंस को लिंक-टाइम पर कई परिभाषाएं उपलब्ध हैं, यह धारणा है कि ये परिभाषाएं सभी (उम्मीद है) समान हैं (मैं निश्चित रूप से inline लिंकेज विनिर्देश के साथ घोषित कार्यों का जिक्र कर रहा हूं, कम्पाइलर या लिंक-टाइम-ऑप्टिमाइज़र वास्तव में इनलाइनों में कार्य करने के लिए नहीं।)

तो आम लिंकर्स आम तौर पर क्या करते हैं जब वे फ़ंक्शन के कई परिभाषाओं का सामना करते हैं? विशेष रूप से:

  • क्या सभी परिभाषाएं अंतिम निष्पादन योग्य या साझा-लाइब्रेरी में शामिल हैं?
  • एक ही परिभाषा के खिलाफ समारोह लिंक के सभी invocations करते हैं?
  • क्या एक या अधिक सी और सी ++ आईएसओ मानकों के लिए आवश्यक उपरोक्त प्रश्नों के उत्तर हैं, और यदि नहीं, तो क्या सबसे सामान्य प्लेटफार्म एक ही काम करते हैं?

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


यदि फ़ंक्शन, वास्तव में, इनलाइन है, तो लिंक करने के लिए कुछ भी नहीं है यह तब होता है जब, किसी भी कारण के लिए, संकलक फ़ंक्शन इनलाइन को विस्तारित करने का निर्णय नहीं करता है कि उसे फ़ंक्शन के आउट-ऑफ-लाइन संस्करण को उत्पन्न करना है। यदि कंपाइलर एक से अधिक अनुवाद इकाई के लिए फ़ंक्शन का एक आउट-ऑफ-लाइन संस्करण तैयार करता है तो आप एक ही "इनलाइन" फ़ंक्शन के लिए परिभाषा वाले एक से अधिक ऑब्जेक्ट फ़ाइल के साथ समाप्त होते हैं।

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


inline या कोई inline नहीं, सी एक ही प्रोग्राम या लाइब्रेरी में योगदान करने वाले अनुवाद इकाइयों के बीच समान नाम की कई बाह्य परिभाषाओं की अनुमति नहीं देता है। इसके अलावा, यह उसी अनुवाद इकाई में एक ही नाम की कई परिभाषाओं की अनुमति नहीं देता, चाहे वह आंतरिक, बाहरी, या इनलाइन हो। इसलिए, किसी दिए गए अनुवाद इकाई में दिए गए फ़ंक्शंस में दिए गए फ़ंक्शन के अधिकतम दो उपलब्ध परिभाषाएं हो सकती हैं: एक आंतरिक और / या इनलाइन, और एक बाहरी

सी 2011, 6.7.4 / 7 में यह कहना है:

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

(महत्व दिया।)

आपके सवालों के विशिष्ट उत्तर में, फिर, जब वे सी से संबंधित होते हैं:

क्या सभी परिभाषाएं अंतिम निष्पादन योग्य या साझा-लाइब्रेरी में शामिल हैं?

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

एक ही परिभाषा के खिलाफ समारोह लिंक के सभी invocations करते हैं?

सी निर्दिष्ट नहीं करता है, लेकिन यह जवाब "नहीं" होने की अनुमति देता है, यहां तक ​​कि एक ही अनुवाद इकाई के भीतर अलग-अलग कॉल्स के लिए। इसके अलावा, इनलाइन फ़ंक्शंस बाहरी नहीं हैं, इसलिए एक अनुवाद इकाई में परिभाषित कोई इनलाइन फ़ंक्शन कभी भी अलग ट्रांसलेशन यूनिट में निर्धारित फ़ंक्शन द्वारा (सीधे) नहीं कहा जाता है।

क्या एक या अधिक सी और सी ++ आईएसओ मानकों के लिए आवश्यक उपरोक्त प्रश्नों के उत्तर हैं, और यदि नहीं, तो क्या सबसे सामान्य प्लेटफार्म एक ही काम करते हैं?

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

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





inline