यह विंडोज और यूनिक्स जैसी प्रणालियों के बीच एक बहुत प्रसिद्ध अंतर है।
कोई बात नहीं क्या:
- प्रत्येक प्रक्रिया का अपना पता स्थान होता है, जिसका अर्थ है कि प्रक्रियाओं के बीच कोई भी मेमोरी साझा नहीं की जा रही है (जब तक कि आप कुछ अंतर-प्रक्रिया संचार पुस्तकालय या एक्सटेंशन का उपयोग नहीं करते हैं)।
- एक परिभाषा नियम (ओडीआर) अभी भी लागू होता है, जिसका अर्थ है कि आप केवल वैश्विक चर लिंक-टाइम (स्थिर या गतिशील जोड़ने) पर दृश्यमान में से एक परिभाषा हो सकता है।
इसलिए, यहां प्रमुख मुद्दा वास्तव में दृश्यता है ।
सभी मामलों में, static
वैश्विक चर (या फ़ंक्शन) किसी मॉड्यूल (dll / so या निष्पादन योग्य) के बाहर से कभी दिखाई नहीं देते हैं। C ++ मानक के लिए आवश्यक है कि इनमें आंतरिक लिंकेज हो, जिसका अर्थ है कि वे अनुवाद इकाई के बाहर दिखाई नहीं दे रहे हैं (जो एक वस्तु फ़ाइल बन जाती है) जिसमें वे परिभाषित हैं। तो, उस मुद्दे को सुलझाता है।
यह जटिल हो जाता है जब आपके पास extern
वैश्विक चर होते हैं। यहां, विंडोज और यूनिक्स जैसी प्रणाली पूरी तरह से अलग हैं।
विंडोज (.exe और .dll) के मामले में, extern
वैश्विक चर निर्यात किए गए प्रतीकों का हिस्सा नहीं हैं। दूसरे शब्दों में, विभिन्न मॉड्यूल किसी भी तरह से अन्य मॉड्यूल में परिभाषित वैश्विक चरों के बारे में नहीं जानते हैं। इसका मतलब है कि यदि आप प्रयास करते हैं, तो आपको लिंकर की त्रुटियां मिलेंगी, उदाहरण के लिए, एक निष्पादन योग्य बनाने के लिए जो extern
एक DLL में परिभाषित चर का उपयोग करना चाहिए , क्योंकि यह अनुमति नहीं है। आपको उस बाह्य चर की परिभाषा के साथ एक वस्तु फ़ाइल (या स्थिर पुस्तकालय) प्रदान करने की आवश्यकता होगी और इसे निष्पादन योग्य और DLL दोनों के साथ सांख्यिकीय रूप से लिंक किया जाएगा , जिसके परिणामस्वरूप दो अलग-अलग वैश्विक चर (निष्पादन योग्य और DLL से संबंधित एक) होंगे )।
वास्तव में विंडोज में एक वैश्विक चर निर्यात करने के लिए, आपको फ़ंक्शन निर्यात / आयात सिंटैक्स के समान एक सिंटैक्स का उपयोग करना होगा, अर्थात:
#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
वैश्विक चर (या फ़ंक्शंस) को एक्सपोर्ट एक्सपोर्ट के साथ साझा करते हैं । इस मामले में, यदि आप किसी साझा ऑब्जेक्ट फ़ाइल से कहीं भी लोड-टाइम लिंकिंग करते हैं , तो वैश्विक चर साझा किए जाते हैं, अर्थात, एक के रूप में एक साथ लिंक किए जाते हैं। मूल रूप से, यूनिक्स जैसी प्रणाली को इसे बनाने के लिए डिज़ाइन किया गया है ताकि वास्तव में एक स्थिर या गतिशील पुस्तकालय के साथ लिंक करने में कोई अंतर न हो। फिर, ODR बोर्ड भर में लागू होता है: एक extern
वैश्विक चर को मॉड्यूल में साझा किया जाएगा, जिसका अर्थ है कि लोड किए गए सभी मॉड्यूलों में इसकी केवल एक परिभाषा होनी चाहिए।
अंत में, दोनों ही मामलों में, विंडोज या के लिए यूनिक्स सिस्टम, आप कर सकते हैं रन-टाइम , गतिशील पुस्तकालय को जोड़ने, यानी या तो का उपयोग कर LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
या dlopen()
/ dlsym()
/ dlclose()
। उस स्थिति में, आपको मैन्युअल रूप से उपयोग किए जाने वाले प्रत्येक प्रतीक के लिए एक संकेतक प्राप्त करना होगा, और इसमें आपके द्वारा उपयोग किए जाने वाले वैश्विक चर शामिल होंगे। वैश्विक चरों के लिए, आप उपयोग कर सकते हैं GetProcAddress()
या dlsym()
जैसा आप कार्य करते हैं, बशर्ते कि वैश्विक चर निर्यातित प्रतीक सूची (पिछले पैराग्राफ के नियमों द्वारा) का हिस्सा हों।
और निश्चित रूप से, एक आवश्यक अंतिम नोट के रूप में: वैश्विक चर से बचा जाना चाहिए । और मुझे विश्वास है कि आपने जो पाठ उद्धृत किया है ("अस्पष्ट" होने के बारे में) बिल्कुल उसी प्लेटफ़ॉर्म-विशिष्ट अंतर का उल्लेख कर रहा है जिसे मैंने अभी समझाया था (डायनेमिक लाइब्रेरी वास्तव में C ++ मानक द्वारा परिभाषित नहीं हैं, यह प्लेटफ़ॉर्म-विशिष्ट क्षेत्र है, जिसका अर्थ है) बहुत कम विश्वसनीय / पोर्टेबल है)।