c++ - साझा लाइब्रेरी में गतिशील रूप से लिंक होने पर वैश्विक और स्थैतिक चर के साथ क्या होता है?



linker global-variables (1)

विंडोज और यूनिक्स जैसी प्रणालियों के बीच यह एक बहुत प्रसिद्ध अंतर है।

कोई बात नहीं क्या:

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

तो, यहां मुख्य मुद्दा वास्तव में दृश्यता है

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

जहां यह जटिल हो जाता है जब आपके पास extern वैश्विक चर होते हैं। यहां, विंडोज और यूनिक्स जैसी प्रणाली पूरी तरह से अलग हैं।

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

वास्तव में विंडोज में एक वैश्विक चर निर्यात करने के लिए, आपको फ़ंक्शन निर्यात / आयात वाक्यविन्यास के समान वाक्यविन्यास का उपयोग करना होगा, यानी:

#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif

MY_DLL_EXPORT int my_global;

जब आप ऐसा करते हैं, तो वैश्विक चर निर्यात किए गए प्रतीकों की सूची में जोड़ा जाता है और अन्य सभी कार्यों की तरह जोड़ा जा सकता है।

यूनिक्स जैसी वातावरण (जैसे लिनक्स) के मामले में, गतिशील पुस्तकालय, जिसे एक्सटेंशन के साथ "साझा ऑब्जेक्ट" कहा जाता है। .so सभी extern वैश्विक चर (या फ़ंक्शंस) निर्यात करते हैं। इस मामले में, यदि आप किसी भी ऑब्जेक्ट फ़ाइल से कहीं भी लोड-टाइम लिंक करते हैं, तो वैश्विक चर साझा किए जाते हैं, यानी, एक साथ एक साथ जुड़े होते हैं। असल में, यूनिक्स जैसी प्रणालियों को इसे बनाने के लिए डिज़ाइन किया गया है ताकि स्थिर या गतिशील लाइब्रेरी से जुड़ने के बीच वास्तव में कोई अंतर न हो। फिर, ओडीआर बोर्ड भर में लागू होता है: एक extern वैश्विक चर मॉड्यूल में साझा किया जाएगा, जिसका अर्थ है कि इसमें लोड किए गए सभी मॉड्यूल में केवल एक परिभाषा होनी चाहिए।

आखिरकार, दोनों मामलों में, विंडोज या यूनिक्स जैसी प्रणालियों के लिए, आप गतिशील लाइब्रेरी के रन-टाइम लिंकिंग कर सकते हैं, यानी dlsym() / GetProcAddress() / FreeLibrary() या dlopen() / dlsym() / dlclose() । उस स्थिति में, आपको उन प्रतीकों में से प्रत्येक को मैन्युअल रूप से एक पॉइंटर प्राप्त करना होगा, जिसका उपयोग आप करना चाहते हैं, और इसमें वैश्विक चर शामिल हैं जिन्हें आप उपयोग करना चाहते हैं। वैश्विक चर के लिए, आप GetProcAddress() या dlsym() का उपयोग उसी तरह कर सकते हैं जैसे आप कार्यों के लिए करते हैं, बशर्ते वैश्विक चर निर्यातित प्रतीक सूची (पिछले पैराग्राफ के नियमों) का हिस्सा हों।

और निश्चित रूप से, एक आवश्यक अंतिम नोट के रूप में: वैश्विक चर से बचा जाना चाहिए । और मेरा मानना ​​है कि आपके द्वारा उद्धृत पाठ (चीजों के बारे में "अस्पष्ट" होने के बारे में) प्लेटफॉर्म-विशिष्ट मतभेदों का जिक्र कर रहा है जो मैंने अभी समझाया है (गतिशील पुस्तकालयों को वास्तव में सी ++ मानक द्वारा परिभाषित नहीं किया गया है, यह प्लेटफ़ॉर्म-विशिष्ट क्षेत्र है, जिसका अर्थ है बहुत कम विश्वसनीय / पोर्टेबल है)।

मैं समझने की कोशिश कर रहा हूं कि क्या होता है जब ग्लोबल्स और स्थिर चर के साथ मॉड्यूल गतिशील रूप से किसी एप्लिकेशन से जुड़े होते हैं। मॉड्यूल द्वारा, मेरा मतलब है कि प्रत्येक प्रोजेक्ट एक समाधान में है (मैं विजुअल स्टूडियो के साथ बहुत काम करता हूं!)। ये मॉड्यूल या तो * .lib या * .dll या * .exe में बनाए गए हैं।

मैं समझता हूं कि किसी एप्लिकेशन के बाइनरी में डेटा सेगमेंट में सभी व्यक्तिगत अनुवाद इकाइयों (ऑब्जेक्ट फाइल) का वैश्विक और स्थैतिक डेटा होता है (और केवल तभी डेटा सेगमेंट पढ़ता है)।

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

  • और क्या होता है जब एप्लिकेशन रन-टाइम गतिशील लिंकिंग के साथ मॉड्यूल बी का उपयोग करता है?

  • अगर मेरे आवेदन में दो मॉड्यूल हैं जो ए और बी दोनों का उपयोग करते हैं, तो नीचे वर्णित ए और बी के ग्लोबल्स की प्रतियां हैं (यदि वे अलग-अलग प्रक्रियाएं हैं)?

  • क्या डीएलएल ए और बी अनुप्रयोगों ग्लोबल्स तक पहुंच प्राप्त करते हैं?

(कृपया अपने कारण बताएं)

MSDN से उद्धरण:

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

और here :

जब गतिशील रूप से मॉड्यूल को जोड़ते हैं, तो यह अस्पष्ट हो सकता है कि अलग-अलग पुस्तकालयों में ग्लोबल्स के अपने उदाहरण हैं या क्या ग्लोबल्स साझा किए गए हैं या नहीं।

धन्यवाद।





dynamic-linking