c++ - विंडोज़ पर__cdecl या__stdcall?




windows dll (2)

दो कॉलिंग सम्मेलनों में सबसे बड़ा अंतर यह है कि " _ _cdecl" कॉलर पर फ़ंक्शन कॉल के बाद स्टैक को संतुलित करने का बोझ रखता है, जो तर्कों की परिवर्तनीय मात्रा के साथ कार्यों की अनुमति देता है। प्रकृति में "__stdcall" सम्मेलन "सरल" है, हालांकि इस संबंध में कम लचीला है।

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

इसलिए, यदि आपके सभी फ़ंक्शन हस्ताक्षरों को स्थैतिक रूप से परिभाषित किया जा रहा है, तो शायद सीडीसीएल नहीं होने पर मैं शायद stdcall की तरफ झुकाऊंगा।

मैं वर्तमान में विंडोज़ के लिए एक सी ++ लाइब्रेरी विकसित कर रहा हूं जिसे डीएलएल के रूप में वितरित किया जाएगा। मेरा लक्ष्य बाइनरी इंटरऑपरेबिलिटी को अधिकतम करना है; अधिक सटीक रूप से, मेरे डीएलएल में कार्य डीएलएल को पुन: संकलित किए बिना एमएसवीसी ++ और मिनजीडब्ल्यू के कई संस्करणों के साथ संकलित कोड से प्रयोग योग्य होना चाहिए। हालांकि, मैं उलझन में हूं कि कौन सा कॉलिंग सम्मेलन सर्वोत्तम है, cdecl या stdcall

कभी-कभी मैं कथन सुनता हूं जैसे "सी कॉलिंग कन्वेंशन एकमात्र एक ही समकक्ष कंपिलर होने की गारंटी देता है", जो कि " cdecl की व्याख्या में कुछ बदलाव हैं, विशेष रूप से मूल्यों को वापस करने के तरीके में " जैसे बयान के साथ विरोधाभास करता है। ऐसा लगता है कि कुछ लाइब्रेरी डेवलपर्स (जैसे libsndfile ) को libsndfile में सी कॉलिंग कन्वेंशन का उपयोग करने के लिए वे किसी भी दृश्यमान समस्या के बिना वितरित नहीं करते हैं।

दूसरी ओर, stdcall कॉलिंग सम्मेलन अच्छी तरह से परिभाषित प्रतीत होता है। जो मुझे बताया गया है, उससे सभी विंडोज कंपाइलरों को मूल रूप से इसका पालन करना आवश्यक है क्योंकि यह Win32 और COM के लिए उपयोग किया जाने वाला सम्मेलन है। यह धारणा पर आधारित है कि Win32 / COM समर्थन के बिना एक विंडोज संकलक बहुत उपयोगी नहीं होगा। फ़ोरम पर पोस्ट किए गए बहुत सारे कोड स्निपेट stdcall रूप में कार्य घोषित करते हैं लेकिन मुझे एक एकल पोस्ट नहीं मिलती है जो स्पष्ट रूप से बताती है कि क्यों

वहां बहुत अधिक विवादित जानकारी है, और मैं जो भी खोज करता हूं वह मुझे अलग-अलग उत्तर देता है जो वास्तव में दोनों के बीच फैसला करने में मेरी सहायता नहीं करता है। मैं एक स्पष्ट, विस्तृत, तर्कसंगत स्पष्टीकरण की तलाश में हूं कि मुझे एक दूसरे को क्यों चुनना चाहिए (या दोनों बराबर क्यों हैं)।

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


मैंने अभी कुछ वास्तविक दुनिया परीक्षण किया है (एमएलवीसी ++ और मिनजीडब्ल्यू के साथ डीएलएल और अनुप्रयोगों को संकलित करना, फिर उन्हें मिलाकर)। जैसा कि प्रतीत होता है, मेरे पास cdecl कॉलिंग सम्मेलन के साथ बेहतर परिणाम थे।

अधिक विशेष रूप से: stdcall साथ समस्या यह है कि बाहरी extern "C" का उपयोग करते समय भी एमएसवीसी ++ डीएलएल निर्यात तालिका में नाम बदलता है। उदाहरण के लिए foo [email protected] बन जाता है। यह केवल तब होता है जब __declspec(dllexport) का उपयोग करते हैं, डीईएफ फ़ाइल का उपयोग करते समय नहीं; हालांकि, डीईएफ फाइलें मेरी राय में रखरखाव परेशानी हैं, और मैं उनका उपयोग नहीं करना चाहता हूं।

एमएसवीसी ++ नाम मैंगलिंग दो समस्याएं उत्पन्न करता है:

  • डीएलएल पर GetProcAddress का उपयोग थोड़ा और जटिल हो जाता है;
  • डिफ़ॉल्ट रूप से MinGW सजाए गए नामों के लिए एक अंडरस्कोर प्रीपेड नहीं करता है (उदाहरण के लिए [email protected] बजाय [email protected] उपयोग करेगा), जो लिंकिंग को जटिल बनाता है। इसके अलावा, यह डीएलएल के "गैर-अंडरस्कोर संस्करण" को देखने का जोखिम पेश करता है और अनुप्रयोगों को जंगली में पॉप अप करता है जो "अंडरस्कोर संस्करण" के साथ असंगत हैं।

मैंने cdecl सम्मेलन की कोशिश की है: एमएसवीसी ++ और मिनजीडब्ल्यू के बीच अंतःक्रियाशीलता पूरी तरह से काम करता है, बॉक्स के बाहर, और नाम डीएलएल निर्यात तालिका में अवांछित रहते हैं। यह वर्चुअल तरीकों के लिए भी काम करता है।

इन कारणों से, cdecl मेरे लिए एक स्पष्ट विजेता है।







binary-compatibility