एक इनबिल्ट फ़ंक्शन में स्थिर चर


85

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

वैसे भी, असली सवाल यह है कि इस फ़ंक्शन के अंदर स्थिर चर क्या होता है? मैं कितनी प्रतियों के साथ समाप्त होता हूं?

जवाबों:


106

मुझे लगता है कि आप यहाँ कुछ याद कर रहे हैं।

स्थिर कार्य?

किसी फ़ंक्शन को स्थिर घोषित करने से वह अपनी संकलन इकाई में "छिपा हुआ" हो जाएगा।

नाम स्थान स्कोप (3.3.6) में आंतरिक लिंकेज है यदि यह नाम है

- एक चर, फ़ंक्शन या फ़ंक्शन टेम्पलेट जिसे स्पष्ट रूप से स्थिर घोषित किया गया है;

3.5 / 3 - सी ++ 14 (n3797)

जब किसी नाम में आंतरिक जुड़ाव होता है, तो उसे निरूपित करने वाली इकाई को उसी अनुवाद इकाई में अन्य स्कोप के नामों से संदर्भित किया जा सकता है।

3.5 / 2 - सी ++ 14 (n3797)

यदि आप हेडर में इस स्थिर फ़ंक्शन को घोषित करते हैं, तो इस हेडर सहित सभी संकलन इकाइयों की फ़ंक्शन की अपनी प्रतिलिपि होगी।

बात यह है कि यदि उस फ़ंक्शन के अंदर स्थिर चर हैं, तो इस हेडर सहित प्रत्येक संकलन इकाई का अपना निजी संस्करण भी होगा।

इनलाइन फ़ंक्शन?

इनलाइन की घोषणा करना इसे इनलाइनिंग के लिए एक उम्मीदवार बनाता है (इसका आजकल सी ++ में बहुत अधिक मतलब नहीं है, क्योंकि कंपाइलर इनलाइन होगा या नहीं, कभी-कभी इस तथ्य को अनदेखा करना कि कीवर्ड इनलाइन मौजूद है या अनुपस्थित है):

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

7.1.2 / 2 - C ++ 14 (n3797)

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

अंदर घोषित किए गए स्थिर चरों के लिए, मानक विशेष रूप से एक कहता है, और उनमें से केवल एक:

एक बाहरी इनलाइन फ़ंक्शन में एक स्थिर स्थानीय चर हमेशा एक ही ऑब्जेक्ट को संदर्भित करता है।

7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)

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

इसका लाभ "स्थिर" है (अर्थात इसे हेडर में परिभाषित किया जा सकता है) इसकी खामियों के बिना (यह सबसे अधिक बार मौजूद है यदि यह इनलेट नहीं है)

स्थिर स्थानीय चर?

स्टेटिक लोकल वेरिएबल्स का कोई लिंकेज नहीं है (उन्हें उनके दायरे से बाहर के नाम से संदर्भित नहीं किया जा सकता है), लेकिन स्टैटिक स्टोरेज की अवधि है (यानी यह वैश्विक है, लेकिन इसका निर्माण और विनाश विशिष्ट नियमों का पालन करता है)।

स्थिर + इनलाइन?

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

लेखक के अतिरिक्त प्रश्न का उत्तर

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

जब फ़ंक्शन केवल "इनलाइन" होता है, तो स्थैतिक चर की केवल एक प्रति होती है।

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

असली सवाल अब यह है कि क्या चीजों को इस तरह से माना जाता है, या यदि यह Microsoft C ++ कंपाइलर का एक idiosyncrasy है।

तो मुझे लगता है कि आपके पास ऐसा कुछ है:

void doSomething()
{
   static int value ;
}

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

फ़ंक्शन को सम्मिलित करने से कुछ भी नहीं बदलेगा:

inline void doSomething()
{
   static int value ;
}

केवल एक छिपा हुआ वैश्विक चर होगा। संकलक तथ्य को इनलाइन करने की कोशिश करेगा कोड इस तथ्य को नहीं बदलेगा कि केवल एक वैश्विक छिपा हुआ चर है।

अब, यदि आपका कार्य स्थिर घोषित किया गया है:

static void doSomething()
{
   static int value ;
}

फिर यह प्रत्येक संकलन इकाई के लिए "निजी" है, जिसका अर्थ है कि प्रत्येक सीपीपी फ़ाइल जिसमें हेडर शामिल है जहां स्थिर फ़ंक्शन घोषित किया गया है, समारोह की अपनी निजी प्रतिलिपि होगी, जिसमें वैश्विक छिपी चर की अपनी निजी प्रतिलिपि भी शामिल है, इस प्रकार जितनी अधिक चर हेडर सहित संकलन इकाइयाँ हैं।

"स्थिर" चर के साथ "इनलाइन" को "स्थिर" चर के साथ जोड़ना:

inline static void doSomething()
{
   static int value ;
}

इस "इनलाइन" कीवर्ड को नहीं जोड़ने का एक ही परिणाम है, जहां तक ​​स्थिर वैरिएबल का संबंध है।

तो VC ++ का व्यवहार सही है, और आप "इनलाइन" और "स्थिर" के वास्तविक अर्थ को गलत कर रहे हैं।


मुझे लगता है कि आप उल्लेख करने के लिए एक महत्वपूर्ण बिंदु को याद कर रहे हैं, कि लिंकिंग चरण में इनलाइन फ़ंक्शन में घोषित सभी स्थिर चर एक में हल हो जाएंगे, क्या मैं गलत हूं?
user14416

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

1
@paercebal इन inline void doSomething() { static int value ; }, फ़ंक्शन में बाहरी लिंकेज है; यह एक ODR उल्लंघन है अगर यह एक हेडर में दिखाई देता है जो दो अलग-अलग इकाइयों से शामिल है
MM

@MM आपका क्या मतलब है? आपका कार्य है inline, यह ODR का उल्लंघन नहीं कर सकता है।
रुस्लान

@ रुस्लान एक गैर-अनुक्रमिक है
एमएम

39

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

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


2
AFAICT, आप यहां जो कह रहे हैं, उसमें आप पूरी तरह से सही हैं। मुझे समझ में नहीं आ रहा है कि लोग इस जवाब को वोट क्यों दे रहे हैं। मेरा एकमात्र अनुमान है कि वे "चर की कई प्रतियां" तक पढ़ते हैं, और फिर रुक जाते हैं! :( वैसे भी मुझसे एक टोकन (+1)।
रिचर्ड कॉर्डन

3
जब लोग इस बारे में पूछते हैं कि कंपाइलर + लिंकर का क्या मतलब है, क्योंकि आप ऑब्जेक्ट फाइल्स नहीं चला सकते हैं। तो यह उत्तर सही है लेकिन पूरी तरह से व्यर्थ है।
इवान डार्क

1
क्योंकि लोग अज्ञानी हैं। यह अधिक उन्नत प्रश्न है और सभी को चर्चा में भेद करना चाहिए।
सोगार्टार

13

मैंने मार्क रैंसम के उत्तर को सहायक पाया - कि संकलक स्थिर चर की कई प्रतियाँ बनाता है, लेकिन लिंकर एक को चुनता है और इसे सभी अनुवाद इकाइयों में लागू करता है।

कहीं और मुझे यह मिला:

देखें [dcl.fct.spec] / 4

[..] बाहरी लिंकेज के साथ एक इनलाइन फ़ंक्शन का सभी अनुवाद इकाइयों में समान पता होगा। एक बाहरी इनलाइन फ़ंक्शन में एक स्थिर स्थानीय चर हमेशा एक ही ऑब्जेक्ट को संदर्भित करता है। एक बाहरी इनलाइन फ़ंक्शन में एक स्ट्रिंग शाब्दिक विभिन्न अनुवाद इकाइयों में एक ही वस्तु है।

मेरे पास जाँच करने के लिए मानक की एक प्रति नहीं है, लेकिन यह VS एक्सप्रेस 2008 में असेंबली की जांच करने के मेरे अनुभव से मेल खाता है


5

यह इस तरह से माना जाता है। "स्टेटिक" उस कंपाइलर को बताता है जिसे आप फ़ंक्शन को संकलन इकाई के लिए स्थानीय बनाना चाहते हैं, इसलिए आप प्रति संकलन इकाई की एक प्रति चाहते हैं और फ़ंक्शन की प्रति आवृत्ति स्थिर चर की एक प्रति चाहते हैं।

"इनलाइन" आपको संकलक को बताना चाहता था कि आप फ़ंक्शन को इनलाइन करना चाहते हैं; आजकल, यह बस के रूप में लेता है "यह ठीक है अगर कोड की कई प्रतियां हैं, तो सुनिश्चित करें कि यह समान फ़ंक्शन है"। तो हर कोई स्थिर चर साझा करता है।

नोट: यह उत्तर मूल पोस्टर के उत्तर के जवाब में लिखा गया था जो कि खुद को पोस्ट किया गया था।


1
वह 'इनलाइन फंक्शन' में 'स्टैटिक वेरिएबल्स' के बारे में पूछ रहा है, स्टैटिक फंक्शन में वेरिएबल नहीं।
रिचर्ड कॉर्डेन

हम उस पर सहमत हैं, लेकिन आप सही हैं: उत्तर को संदर्भ में वापस रखने के लिए एक संपादन की आवश्यकता है।
राफेल सेंट-पियरे

मुझे यह भी पता चला। तो दोनों में से कौन सा है? inlineफ़ंक्शन को इनलाइन करने का कारण बनता है या एकाधिक प्रतियां होना ठीक है?
वासिलिस

@Vassilis दोनों सही हैं, हालांकि इनलाइनिंग का कारणinline नहीं है , यह सिर्फ इसका सुझाव देता है, और यह एक से अधिक परिभाषा के लिए अनुमति देता है (लेकिन एक ही संकलन इकाई में नहीं)।
राफेल सेंट-पियरे

3

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

जब फ़ंक्शन केवल "इनलाइन" होता है, तो स्थैतिक चर की केवल एक प्रति होती है।

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

असली सवाल अब यह है कि क्या चीजें इस तरह से होनी चाहिए, या यदि यह Microsoft C ++ कंपाइलर की एक विचारधारा है।


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

अपनी सेटिंग्स के बारे में निश्चित नहीं है लेकिन कंपाइलर इस मामले में सही तरीके से काम कर रहा है। हालाँकि, आप एक इकाई परीक्षण को शामिल करना चाहते हैं, यदि आप सड़क के नीचे कुछ गैर अनुरूप संकलक में चलते हैं।
रॉबर्ट गोल्ड

-1

इनलाइनिंग का अर्थ है कि निष्पादन योग्य कोड (निर्देश) कॉलिंग फ़ंक्शन के कोड में इनबिल्ट है। संकलक ऐसा करने का विकल्प चुन सकता है, भले ही आपने इसे पूछा हो। फ़ंक्शन में घोषित चर (डेटा) पर इसका कोई प्रभाव नहीं है।


-2

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


-2

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


-2

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.