2012-04-29 11 views
5

हम कई मायनों में मुख्य कार्य लिख सकते हैं होने,कैसे सीआरटी मुख्य कहता है, अलग अलग पैरामीटर

  1. int main()
  2. int main(int argc,char *argv[])
  3. int main(int argc,char *argv[],char * environment)

कैसे रन-टाइम सीआरटी समारोह जानता है जो मुख्य कहा जाना चाहिए कृपया यहां ध्यान दें, मैं यूनिकोड समर्थित या नहीं के बारे में नहीं पूछ रहा हूं।

उत्तर

5

स्वीकृत उत्तर गलत है, सीआरटी में मुख्य() घोषणा की पहचान करने के लिए कोई विशेष कोड नहीं है।

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

यही कारण है कि printf() फ़ंक्शन काम कर सकता है, इसमें तर्कों की एक चर संख्या है। एक ज्ञात स्थिति में एक तर्क के साथ, पहला।

+0

यह शायद 32 बिट विंडोज सी रनटाइम सटीक है। लेकिन अन्य प्लेटफार्मों के बारे में क्या है जहां एबीआई अलग है? उदाहरण के लिए x64 जहां सीडीसीएल के लिए भी रजिस्टरों में पैरामीटर पास किए जाते हैं। और इस 'int मुख्य (डबल डी)' की तरह घोषित 'मुख्य' फ़ंक्शन के अनुरूप क्या है? और मानक में यह कहता है कि सभी 'मुख्य' कार्यों को '__cdecl' का उपयोग करना चाहिए जो मानक का हिस्सा भी नहीं है? और 'विनमेन' के बारे में क्या? –

+0

ठीक है, कम से कम आपके उत्तर की पहली वाक्य अब सटीक है। ;-) –

+0

खट्टा अंगूर डेविड? आपका उत्तर सही हो सकता है, मैं बस ऐसे किसी भी कंपाइलर को नहीं जानता जो प्रतिबिंब के प्रकार का समर्थन करता है जिसे इसे काम करने के लिए आवश्यक होगा। मैं केवल उन में से 8 में उपयोग किए गए प्रस्तावों की पेशकश कर सकता हूं जिनके बारे में मैंने काफी करीब अध्ययन किया था, वे सभी एक सीडीईसी कॉलिंग सम्मेलन का इस्तेमाल करते थे। शायद क्योंकि यह लागू करना बहुत आसान है, हालांकि कोड उत्पन्न करने में इतना आसान नहीं है। प्रतिबिंब सी में एक बहुत ही असामान्य विशेषता है। आप शायद ऐसे कंपाइलर का उदाहरण देकर इसे और अधिक समझदार बना सकते हैं? –

4

सामान्य में, संकलक/लिंकर सिस्टम स्टार्टअप समारोह से अपने सी या सी ++ main कार्य करने के लिए अनुकूल करने के लिए कि main है कि आप उपयोग कर रहे हैं विशेष रूप समझते हैं और उसके बाद कोड को शामिल करने की आवश्यकता होगी।

यह सच है कि विशिष्ट प्लेटफॉर्म पर विशिष्ट कंपाइलर्स इसके जवाब में वर्णित विधियों का उपयोग करके ऐसा करने के बिना दूर हो सकते हैं। हालांकि, सभी प्लेटफ़ॉर्म पैरामीटर पास करने के लिए स्टैक का उपयोग नहीं करते हैं, और अनुरूप सी और सी ++ कार्यान्वयन लिखना संभव है जिसमें असंगत पैरामीटर सूचियां हैं। ऐसे मामलों के लिए, फिर संकलक/लिंकर को यह निर्धारित करने की आवश्यकता होगी कि किस प्रकार के main कॉल करें।

+0

मैं सहमत हूं, लेकिन यह कोड को कैसे पहचानता है और उत्पन्न करता है, भले ही हम इसे ओवरलोडिंग के रूप में लें, सी इसका समर्थन नहीं करता है। –

+0

धन्यवाद। जवाब स्वीकार किया गया। –

+0

आपको यह गलत लगता है, मेरा जवाब जांचें। –

0

पहले, main समारोह जीसीसी में विशेष रूप से इलाज किया जाता है (उदाहरण के लिए जीसीसी 4.7 के स्रोत के पेड़ की फ़ाइल gcc/c-family/c-common.c में main_identifier_node)

और सी 11 और सी ++ 11 मानकों विशिष्ट शब्दों और इसके बारे में विनिर्देश है।

फिर, सी कॉलिंग एबीआई सम्मेलन आम तौर पर होते हैं ताकि अतिरिक्त तर्क अधिक नुकसान न पहुंचे।

तो आप इसके बारे में सोच सकते हैं जैसे कि भाषा विनिर्देश और संकलक दोनों के पास main के "अधिभार" के संबंध में विशिष्ट चीजें हैं।

मुझे यह भी लगता है कि main सामान्य कार्य नहीं हो सकता है। मेरा मानना ​​है कि मानक में कुछ शब्द- जिनके पास अभी नहीं है- उदाहरण हो सकता है main पर अपना पता लेने या पुनरावर्ती करने के लिए मना कर दिया गया है।

अभ्यास में, maincrt*.ogcc से जुड़ी कुछ असेंबली कोड द्वारा संकलित किया गया है। खुशी के बारे में और जानने के लिए gcc -v का उपयोग करें।

1

सी 99 मानक (5.1.2.2.1 कार्यक्रम स्टार्टअप) का कहना है एक कार्यान्वयन मुख्य() फ़ंक्शन के लिए लागू करता है कोई प्रोटोटाइप कि, और एक कार्यक्रम में से किसी के रूप में यह निर्धारित कर सकते हैं कि:

1) int मुख्य (शून्य);

2) int मुख्य (int argc, char * argv []);

या अर्थात् 2 के बराबर समान रूप से), उदाहरण के लिए

2 ') int मुख्य (int argc, char ** argv);

या अन्य कार्यान्वयन परिभाषित तरीकों में। यह जनादेश है कि प्रोटोटाइप:

3) int मुख्य (int argc, char * argv [], char * envp []);

का इरादा व्यवहार होगा - हालांकि प्रोटोटाइप को संकलित करना होगा, क्योंकि किसी भी प्रोटोटाइप को संकलित करना होगा। 3) अन्य कंपेलरों के बीच जीसीसी और माइक्रोसॉफ्ट सी द्वारा समर्थित है। (एनबी। प्रश्नकर्ता का तीसरा प्रोटोटाइप char * envp [] के बजाय char * envp है, चाहे दुर्घटना हो या क्योंकि उसके पास कुछ अन्य कंपाइलर है)।

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

#include <stdio.h> 

void main(double d, char c) 
{ 
    printf("%lf\n",d); 
    putchar(c); 
} 

यदि आप एक डबल पास करने का तरीका और इस कार्यक्रम के लिए एक चार सीधे मिल सकता है तार की एक सरणी के माध्यम से नहीं।

इन अवलोकनों को प्रयोगात्मक कार्यक्रमों के लिए असेंबली भाषा सूची सक्षम करके सत्यापित किया जा सकता है।

कैसे संकलक के मानक CRT हमें परमिट) मुख्य के उत्पन्न कार्यान्वयन (आह्वान करने के लिए का सवाल कैसे main() संकलक को परिभाषित किया जा सकता का सवाल से अलग है।

दोनों जीसीसी और एमएस सी के लिए, मुख्य() किसी भी तरह से परिभाषित किया जा सकता है। प्रत्येक मामले में हालांकि कार्यान्वयन के मानक सीआरटी, एएफआईके, मुख्य() के अनुसार तर्कों को उत्तीर्ण करने का समर्थन करता है 3)। तो 1) - 2 ') में अतिरिक्त तर्कों को अनदेखा करके अपेक्षित व्यवहार भी होगा, और हमारे पास गैर-मानक रनटाइम प्रदान करने के अलावा कोई अन्य विकल्प नहीं है।

हंस पासेंट का जवाब आकस्मिक रूप से भ्रामक लगता है कि argc फ़ंक्शन को बताता है कि कितने बाद के तर्क printf() के पहले तर्क के रूप में उपभोग करते हैं। यदि argc बिल्कुल मौजूद है, तो यह केवल दूसरे तर्क argv के रूप में पारित सरणी में तत्वों की संख्या को दर्शाता है। यह इंगित नहीं करता है कि मुख्य() में कितने तर्क पारित किए जाते हैं। दोनों जीसीसी और एमएस सी आंकड़ा बाहर कैसे क्या तर्क प्रोटोटाइप आपके द्वारा लिखा गया पार्स करने से उम्मीद कर रहे हैं - अनिवार्य रूप से क्या एक संकलक उन को छोड़कर किसी भी समारोह के साथ करता है, printf की तरह(), कि परिभाषित कर रहे हैं तर्क के परिवर्तनशील लेने के लिए।

मुख्य() तर्कों की एक चर संख्या नहीं लेता है।यह आपके परिभाषा में निर्दिष्ट तर्क लेता है, और सामान्य कंपेलरों के मानक सीआरटी उन्हें मानते हैं (int, char * [], char * [])।

2

हम्म। ऐसा लगता है कि शायद वर्तमान में स्वीकृत उत्तर, जो इंगित करता है कि पहले स्वीकृत उत्तर गलत है, स्वयं गलत है। इस प्रश्न के टैग से संकेत मिलता है कि यह सी ++ के साथ-साथ सी पर भी लागू होता है, इसलिए मैं सी ++ स्पेक पर रहूंगा, सी 99 नहीं। अन्य सभी स्पष्टीकरण या तर्कों के बावजूद, इस प्रश्न का प्राथमिक उत्तर यह है कि "मुख्य() को कार्यान्वयन-परिभाषित तरीके से विशेष माना जाता है।" मेरा मानना ​​है कि डेविड का जवाब तकनीकी रूप से हंस से अधिक सही है, लेकिन मैं इसे समझाऊंगा अधिक जानकारी में ....

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

सी ++ स्पेक के अनुसार मुख्य() फ़ंक्शन का इलाज कार्यान्वयन-परिभाषित किया गया है (धारा 3.6, "प्रारंभ और समाप्ति" देखें)। यह संभावना है कि अधिकांश कार्यान्वयन 'कंपाइलर्स मुख्य() को बाहरी "सी" लिंकेज के समान रूप से मुख्य रूप से (गैर) सजाए गए राज्य में मुख्य() छोड़कर इसका इलाज करते हैं ताकि उसके फ़ंक्शन प्रोटोटाइप पर ध्यान दिए बिना, इसके लिंकर प्रतीक समान हों। वैकल्पिक रूप से, कार्यान्वयन के लिए लिंकर प्रतीक तालिका के माध्यम से स्कैन करने के लिए पर्याप्त स्मार्ट हो सकता है जिसके किसी भी सजाए गए नाम को "[int | void] main (...)" के किसी रूप में हल किया गया है (ध्यान दें कि वापसी प्रकार के रूप में शून्य है स्वयं एक कार्यान्वयन-विशिष्ट चीज है, क्योंकि spec स्वयं ही कहता है कि मुख्य प्रकार का वापसी ('' होना चाहिए)। एक बार ऐसा प्रतीक उपलब्ध प्रतीकों में पाया जाता है, तो लिंकर बस उस स्थान का उपयोग कर सकता है जहां स्टार्टअप कोड "मुख्य()" को संदर्भित करता है, इसलिए सटीक प्रतीक नाम को विशेष रूप से किसी भी चीज़ से मेल नहीं करना पड़ेगा; यह भी wmain() या अन्य हो सकता है, जब तक कि लिंकर जानता है कि किस बदलाव की तलाश है, या संकलक एक ही प्रतीक नाम के साथ सभी भिन्नताओं को समाप्त करता है।

यह भी ध्यान देने योग्य कुंजी यह है कि spec का कहना है कि मुख्य() को अधिभारित नहीं किया जा सकता है, इसलिए लिंकर को मुख्य रूप से विभिन्न रूपों() के कई रूपों के कई उपयोगकर्ता कार्यान्वयन के बीच "चुनना" नहीं होना चाहिए। यदि यह एक से अधिक पाता है, तो यह एक डुप्लिकेट प्रतीक त्रुटि (या अन्य समान त्रुटि) है, भले ही तर्क सूचियां मेल न हों। और हालांकि सभी कार्यान्वयन की अनुमति देते हैं "होगा" दोनों

int main() { /* ... */ } 

और

int main(int argc, char* argv[]) { /* ... */ } 

वे भी संस्करण आपको लगता है कि एक वातावरण स्ट्रिंग सरणी सूचक भी शामिल है दिखाने के लिए, और किसी भी अन्य सहित अन्य तर्क सूचियों, अनुमति देने के लिए अनुमति दी जाती है भिन्नता जो किसी दिए गए कार्यान्वयन में समझ में आता है।

जैसा कि हंस इंगित करता है, विजुअल स्टूडियो कंपाइलर का सीडीसीएल कॉलिंग कन्वेंशन (और कई अन्य कंपाइलर्स के सम्मेलन को कॉल करना) एक ढांचा प्रदान करता है जिसमें एक कॉलर कॉलिंग पर्यावरण स्थापित कर सकता है (यानी स्टैक, या एबीआई-परिभाषित रजिस्ट्रार, या कुछ संयोजन दोनों में से) इस तरह से तर्कों की एक परिवर्तनीय संख्या पारित की जा सकती है, और जब कॉलली लौटाती है, तो कॉलर सफाई के लिए ज़िम्मेदार होता है (स्टैक से प्रयुक्त तर्क स्थान पॉपिंग करता है, या रजिस्टरों के मामले में, कुछ भी करने की आवश्यकता नहीं होती है सफाई के लिए)। यह सेटअप स्टार्टअप कोड को खुद को आवश्यक रूप से अधिक पैरामीटर पास करने के लिए अच्छी तरह से उधार देता है, और उपयोगकर्ता के मुख्य() कार्यान्वयन का उपयोग करने के लिए स्वतंत्र है या इनमें से किसी भी तर्क का उपयोग नहीं किया गया है, जैसा कि कई प्लेटफार्मों के विभिन्न रूपों के उपचार के मामले में है मुख्य() आप अपने प्रश्न में सूचीबद्ध हैं।हालांकि, यह एकमात्र तरीका नहीं है कि एक कंपाइलर + लिंकर इस लक्ष्य को पूरा कर सकता है: इसके बजाय, लिंकर आपके मुख्य() की परिभाषा के आधार पर स्टार्टअप कोड के विभिन्न संस्करणों के बीच चयन कर सकता है। ऐसा करने से विभिन्न प्रकार की मुख्य() तर्क सूचियां मिलेंगी जो अन्यथा सीडीईसीएल कॉलर-क्लीनअप मॉडल के साथ असंभव होंगी। और चूंकि यह सब कार्यान्वयन-परिभाषित है, यह सी ++ spec के प्रति कानूनी है, जब तक कि संकलक + लिंकर कम से कम दो संयोजनों का समर्थन करता है (int main() और int main(int, char**))।

संबंधित मुद्दे