c++ - __Stdcall का अर्थ और उपयोग क्या है?



windows calling-convention (9)

मैं इन दिनों __stdcall भर में आया हूँ।

एमएसडीएन स्पष्ट रूप से स्पष्ट नहीं करता है कि इसका वास्तव में क्या अर्थ है, इसका उपयोग कब और क्यों किया जाना चाहिए।

मैं सराहना करता हूं अगर कोई स्पष्टीकरण प्रदान करेगा, अधिमानतः एक उदाहरण या दो के साथ।


Answers

यह एक समारोह के लिए एक कॉलिंग सम्मेलन निर्दिष्ट करता है। एक कॉलिंग सम्मेलन नियमों का एक सेट है कि फ़ंक्शन को पैरामीटर कैसे पास किए जाते हैं: किस क्रम में, प्रति पता या प्रति प्रति, जो पैरामीटर (कॉलर या कैली) को साफ करना है।


यह एक कॉलिंग सम्मेलन है कि WinAPI कार्यों को ठीक से बुलाया जाना चाहिए। एक कॉलिंग सम्मेलन नियमों का एक सेट है कि पैरामीटर को फ़ंक्शन में कैसे पारित किया जाता है और फ़ंक्शन से वापसी मूल्य कैसे पारित किया जाता है।

यदि कॉलर और कॉल किया गया कोड अलग-अलग सम्मेलनों का उपयोग करता है तो आप अपरिभाषित व्यवहार (जैसे अजीब दिखने वाले दुर्घटना ) में भाग लेते हैं।

सी ++ कंपाइलर्स डिफ़ॉल्ट रूप से __stdcall का उपयोग नहीं करते हैं - वे अन्य सम्मेलनों का उपयोग करते हैं। तो सी ++ से WinAPI फ़ंक्शंस को कॉल करने के लिए आपको यह निर्दिष्ट करने की आवश्यकता है कि वे __stdcall का उपयोग करते हैं - यह आमतौर पर विंडोज़ एसडीके हेडर फाइलों में किया जाता है और फ़ंक्शन पॉइंटर्स घोषित करते समय भी आप इसे करते हैं।


__stdcall एक कॉलिंग सम्मेलन है: यह निर्धारित करने का एक तरीका है कि किसी फ़ंक्शन (स्टैक या रजिस्टरों पर) पैरामीटर कैसे पास किए जाते हैं और फ़ंक्शन रिटर्न (कॉलर या कैली) के बाद सफाई के लिए कौन जिम्मेदार होता है।

रेमंड चेन ने प्रमुख x86 कॉलिंग सम्मेलनों के बारे में एक ब्लॉग लिखा, और वहां एक अच्छा कोडप्रोजेक्ट आलेख भी है।

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


सी / सी ++ में सभी कार्यों में एक विशेष कॉलिंग सम्मेलन होता है। कॉलिंग कन्वेंशन का मुद्दा यह निर्धारित करना है कि कॉलर और कैली के बीच डेटा कैसे पारित किया जाता है और कॉल स्टैक को साफ करने जैसे संचालन के लिए कौन जिम्मेदार है।

खिड़कियों पर सबसे लोकप्रिय कॉलिंग सम्मेलन हैं

  • stdcall
  • cdecl
  • clrcall
  • fastcall
  • thiscall

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

कॉलिंग सम्मेलन यहां दस्तावेज हैं

रेमंड चेन ने यहां से शुरू होने वाले विभिन्न कॉलिंग सम्मेलनों (5 भागों) के इतिहास पर एक लंबी श्रृंखला भी की।


__stdcall एक कॉलिंग सम्मेलन को दर्शाता है (कुछ विवरणों के लिए यह पीडीएफ देखें)। इसका अर्थ यह है कि यह निर्दिष्ट करता है कि फ़ंक्शन तर्क कैसे धक्का दिए जाते हैं और ढेर से पॉप किए जाते हैं, और कौन जिम्मेदार है।

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


परंपरागत रूप से, सी फ़ंक्शन कॉल कॉलर के साथ कुछ पैरामीटर को स्टैक पर दबाकर, फ़ंक्शन को कॉल करने और फिर उन धक्का वाले तर्कों को साफ़ करने के लिए स्टैक पॉपिंग के साथ किए जाते हैं।

/* example of __cdecl */
push arg1
push arg2
push arg3
call function
add sp,12 // effectively "pop; pop; pop"

नोट: डिफ़ॉल्ट सम्मेलन - ऊपर दिखाया गया - __cdecl के रूप में जाना जाता है।

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

/* example of __stdcall */
push arg1 
push arg2 
push arg3 
call function // no stack cleanup - callee does this

यह एक मामूली तकनीकी विवरण की तरह दिखता है, लेकिन अगर कॉलर और कैली के बीच स्टैक को प्रबंधित किया जाता है, इस पर असहमति है, तो ढेर को इस तरह से नष्ट कर दिया जाएगा कि उसे पुनर्प्राप्त करने की संभावना नहीं है। चूंकि __stdcall क्लीनअप को ढेर करता है, इसलिए यह कार्य करने के लिए (बहुत छोटा) कोड प्रत्येक कॉलर में डुप्लीकेट होने की बजाय केवल एक स्थान पर पाया जाता है क्योंकि यह __cdecl में है। यह कोड को बहुत छोटा बनाता है, हालांकि आकार प्रभाव केवल बड़े कार्यक्रमों में दिखाई देता है।

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

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

__cdecl (सीएल / जीडी ...)

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

__stdcall (सीएल / जीजे ...)

इन फ़ंक्शन नामों को अंडरस्कोर के साथ उपसर्ग किया गया है और @ प्लस पास किए गए पैरामीटर के बाइट्स की संख्या के साथ जोड़ा गया है। इस तंत्र से, "गलत" प्रकार, या यहां तक ​​कि पैरामीटर की गलत संख्या के साथ फ़ंक्शन को कॉल करना संभव नहीं है।

__fastcall (सीएल / जीआर ...)

ये फ़ंक्शन नाम @ साइन के साथ शुरू होते हैं और @parameter गिनती के साथ पर्याप्त होते हैं, जैसे कि __stdcall।

उदाहरण:

Declaration                        ----------------------->    decorated name


void __cdecl foo(void);            ----------------------->    _foo

void __cdecl foo(int a);           ----------------------->    _foo

void __cdecl foo(int a, int b);    ----------------------->    _foo

void __stdcall foo(void);          ----------------------->    [email protected]

void __stdcall foo(int a);         ----------------------->    [email protected]

void __stdcall foo(int a, int b);  ----------------------->    [email protected]

void __fastcall foo(void);         ----------------------->    @[email protected]

void __fastcall foo(int a);        ----------------------->    @[email protected]

void __fastcall foo(int a, int b); ----------------------->    @[email protected]

दुर्भाग्य से, इसका उपयोग कब और कब नहीं किया जा सकता है इसके लिए कोई आसान जवाब नहीं है।

__stdcall का अर्थ है कि किसी फ़ंक्शन के तर्क पहले से आखिरी तक स्टैक पर धकेल जाते हैं। यह __cdecl के विपरीत है, जिसका अर्थ है कि तर्कों को अंतिम से पहले तक धक्का दिया जाता है, और __fastcall, जो रजिस्टरों में पहले चार (मुझे लगता है) तर्क देता है, और बाकी स्टैक पर जाते हैं।

आपको सिर्फ यह जानने की जरूरत है कि कैली उम्मीद करता है, या यदि आप लाइब्रेरी लिख रहे हैं, तो आपके कॉलर्स की क्या अपेक्षा है, और सुनिश्चित करें कि आप अपने चुने हुए सम्मेलन को दस्तावेज करते हैं।


जब आप फ़ंक्शन कॉल करते हैं तो बस डालें, यह स्टैक / रजिस्टर में लोड हो जाता है। __stdcall एक सम्मेलन / रास्ता है (दाएं तर्क पहले, फिर तर्क छोड़ दिया ...), __decl एक और सम्मेलन है जिसका उपयोग स्टैक या रजिस्टरों पर फ़ंक्शन को लोड करने के लिए किया जाता है।

यदि आप उनका उपयोग करते हैं तो आप कंप्यूटर को लिंक करने के दौरान फ़ंक्शन को लोड / अनलोड करने के लिए उस विशिष्ट तरीके का उपयोग करने के लिए निर्देश देते हैं और इसलिए आपको कोई मेल नहीं मिला / क्रैश नहीं होगा।

अन्यथा फ़ंक्शन-कैली और फ़ंक्शन-कॉलर प्रोग्राम को क्रैश होने के कारण विभिन्न सम्मेलनों का उपयोग कर सकता है।


यह मेरे पिछले उत्तर का अनुवर्ती है और इसमें C ++ 11 संबंधित सामग्री शामिल है।

पूर्व-आवश्यकताएं : संबंधों का एक प्राथमिक ज्ञान (गणित)।

क्या यह सच है कि सी ++ 11 में कोई अनुक्रम अंक नहीं हैं?

हाँ! यह एकदम सच है।

अनुक्रम अंक को सी ++ 11 में relations बाद अनुक्रमित और अनुक्रमित (और बाद में और अनिश्चित रूप से अनुक्रमित ) द्वारा प्रतिस्थापित किया गया है।

यह 'चीज़ से पहले अनुक्रमित' वास्तव में क्या है?

पहले (§1.9 / 13) अनुक्रमित एक संबंध है जो है:

एक thread द्वारा निष्पादित मूल्यांकन के बीच और एक सख्त आंशिक आदेश 1 प्रेरित करता है

औपचारिक रूप से इसका मतलब है कि किसी भी दो मूल्यांकन (नीचे देखें) A और B , यदि A को B से पहले अनुक्रमित किया गया है , तो A के निष्पादन B के निष्पादन से पहले होगा । यदि A और B से पहले अनुक्रमित नहीं किया गया है तो A पहले अनुक्रमित नहीं किया गया है, तो A और B का अपूर्ण नहीं है 2

मूल्यांकन A और B को अनिश्चित रूप से अनुक्रमित किया जाता है जब A या B को B से पहले अनुक्रमित किया जाता है, लेकिन यह अनिर्दिष्ट है कि 3

[टिप्पणियाँ]
1: एक सख्त आंशिक क्रम एक सेट P पर एक द्विआधारी संबंध "<" जो Asymmetric , और Transitive , यानी, P में सभी a , b , और c , हमारे पास यह है:
........(मैं)। यदि एक <बी तो ¬ (बी <ए) ( asymmetry );
........ (ii)। अगर एक <बी और बी <सी तो एक <सी ( transitivity )।
2: अपरिचित मूल्यांकन का निष्पादन ओवरलैप हो सकता है
3: अनिश्चित रूप से अनुक्रमित मूल्यांकन ओवरलैप नहीं हो सकते हैं , लेकिन पहले इसे निष्पादित किया जा सकता है।

सी ++ 11 के संदर्भ में 'मूल्यांकन' शब्द का अर्थ क्या है?

सी ++ 11 में, सामान्य रूप से एक अभिव्यक्ति (या उप-अभिव्यक्ति) का मूल्यांकन शामिल है:

अब (§1.9 / 14) कहता है:

पूर्ण मूल्य अभिव्यक्ति से जुड़े प्रत्येक मूल्य गणना और साइड इफेक्ट का मूल्यांकन प्रत्येक मूल्य गणना और अगली पूर्ण अभिव्यक्ति के साथ साइड इफेक्ट से पहले किया जाना चाहिए

  • मामूली उदाहरण:

    int x; x = 10; ++x;

    मूल्य गणना और ++x से जुड़े दुष्प्रभाव को मान गणना और x = 10; दुष्प्रभाव के बाद अनुक्रमित किया गया है x = 10;

तो अपरिभाषित व्यवहार और उपर्युक्त चीजों के बीच कुछ संबंध होना चाहिए, है ना?

हाँ! सही।

(§1.9 / 15) में इसका उल्लेख किया गया है

जहां भी ध्यान दिया गया है, अलग-अलग ऑपरेटरों के संचालन और व्यक्तिगत अभिव्यक्तियों के उप-अभिव्यक्तियों के मूल्यांकन के परिणामस्वरूप 4 नहीं हैं

उदाहरण के लिए :

int main()
{
     int num = 19 ;
     num = (num << 3) + (num >> 3);
} 
  1. + ऑपरेटर के संचालन का मूल्यांकन एक-दूसरे के सापेक्ष अपरिचित है।
  2. << और >> ऑपरेटरों के संचालन का मूल्यांकन एक-दूसरे के सापेक्ष अपरिचित है।

4: एक अभिव्यक्ति में जिसे किसी प्रोग्राम के निष्पादन के दौरान एक से अधिक बार मूल्यांकन किया जाता है, इसके उप- अभिव्यक्तियों के अपरिचित और अनिश्चित रूप से अनुक्रमित मूल्यांकनों को विभिन्न मूल्यांकनों में निरंतर प्रदर्शन नहीं किया जाना चाहिए।

(§1.9 / 15) ऑपरेटर के संचालन के मूल्य गणना से पहले ऑपरेटर के ऑपरेटरों की मान गणना अनुक्रमित होती है।

इसका मतलब x + y में x और y की मान गणना गणना (x + y) की मान गणना से पहले अनुक्रमित होती है।

अधिक महत्वपूर्ण बात

(§1.9 / 15) यदि स्केलर ऑब्जेक्ट पर साइड इफेक्ट किसी भी रिश्तेदार के विपरीत नहीं है

(ए) एक ही स्केलर ऑब्जेक्ट पर एक और दुष्प्रभाव

या

(बी) एक ही स्केलर ऑब्जेक्ट के मान का उपयोग करके मूल्य गणना।

व्यवहार अपरिभाषित है

उदाहरण:

int i = 5, v[10] = { };
void  f(int,  int);
  1. i = i++ * ++i; // Undefined Behaviour
  2. i = ++i + i++; // Undefined Behaviour
  3. i = ++i + ++i; // Undefined Behaviour
  4. i = v[i++]; // Undefined Behaviour
  5. i = v[++i]: // Well-defined Behavior
  6. i = i++ + 1; // Undefined Behaviour
  7. i = ++i + 1; // Well-defined Behaviour
  8. ++++i; // Well-defined Behaviour
  9. f(i = -1, i = -1); // Undefined Behaviour (see below)

फ़ंक्शन को कॉल करते समय (चाहे फ़ंक्शन इनलाइन हो या नहीं), प्रत्येक मान गणना और साइड इफेक्ट किसी भी तर्क अभिव्यक्ति से जुड़ा हुआ है, या कॉल फ़ंक्शन को नामित पोस्टफिक्स अभिव्यक्ति के साथ, प्रत्येक अभिव्यक्ति या विवरण के निष्पादन से पहले अनुक्रमित किया जाता है समारोह कहा जाता है। [ नोट: विभिन्न तर्क अभिव्यक्तियों से जुड़े मूल्य गणना और साइड इफेक्ट्स अपूर्ण हैं । - अंत नोट ]

अभिव्यक्तियां (5) , (7) और (8) अपरिभाषित व्यवहार का आह्वान न करें। अधिक विस्तृत स्पष्टीकरण के लिए निम्नलिखित उत्तरों देखें।

अंतिम नोट :

यदि आपको पोस्ट में कोई दोष मिलता है तो कृपया एक टिप्पणी छोड़ दें। पावर-उपयोगकर्ता (प्रतिनिधि> 20000 के साथ) कृपया टाइपो और अन्य गलतियों को ठीक करने के लिए पोस्ट को संपादित करने में संकोच न करें।





c++ windows calling-convention