C ++ में मुख्य () के अंदर कुछ भी घोषित करना कैसे संभव है और अभी तक संकलन के बाद एक कार्यशील अनुप्रयोग है?


86

एक साक्षात्कार में मैं इस तरह एक सवाल के साथ सामना किया गया था:

आपके मित्र ने आपको एकल स्रोत कोड फ़ाइल दी है जो कंसोल पर फाइबोनैचि संख्याओं को प्रिंट करती है। ध्यान दें कि मुख्य () ब्लॉक खाली है और इसके अंदर कोई स्टेटमेंट नहीं है।

यह बताएं कि यह कैसे संभव है (संकेत: वैश्विक उदाहरण!)

मैं वास्तव में इस बारे में जानना चाहता हूं कि ऐसा कैसे संभव हो सकता है!



14
क्योंकि यह कुछ है कि 1) मैंने नहीं सुना था, 2) उपयोगी सामान्य ज्ञान है क्योंकि लोग इसे साक्षात्कार में पूछते हैं, 3) भाषा का एक दिलचस्प आवेदन यह जानने के लिए कि 4) मैं इसे पहचान सकता हूं और चेहरे पर किसी को भी छुरा मार सकता हूं अगर मैं उन्हें वास्तव में उत्पादन कोड में इसका उपयोग करते हुए देखूं तो जंग खाएगी।
सर्वार्थसिद्धि योग

4
एक सक्षम, पेशेवर C ++ प्रोग्रामर को इस प्रश्न का उत्तर पता होगा। यदि इस साक्षात्कार प्रश्न का उद्देश्य यह निर्धारित करना है कि क्या साक्षात्कार किया जा रहा व्यक्ति सक्षम, पेशेवर C ++ प्रोग्रामर है, तो प्रश्न का उत्तर उन्हें नहीं देना चाहिए।
जॉन डिबलिंग

1
एक साक्षात्कार सेटिंग में, एक विकल्प कोड में किसी भी फ़ंक्शन के अंदर तर्क रखना होगा और आउटपुट का उपयोग करके लॉग इन करना होगा assertया #pragma messageआदि। यह संकलन के दौरान आउटपुट को कंसोल पर रीडायरेक्ट करेगा। कार्यक्रम कभी भी पूरी तरह से संकलित नहीं हो सकता है, लेकिन यह सुनिश्चित है कि साक्षात्कार के दौरान आपकी "आउट-ऑफ-द-बॉक्स" सोच दिखाने का एक मजेदार तरीका है। यह उद्धृत प्रश्न को संतुष्ट करता है क्योंकि यह बाइनरी उत्पन्न होने के बारे में कुछ भी उल्लेख नहीं करता है; बल्कि यह सिर्फ एक सी फ़ाइल के बारे में बात करता है जो कंसोल पर "सामान" प्रदर्शित कर सकता है। ;-)
TheCodeArtist

1
क्या यह IOCC के लिए एक साक्षात्कार था ? :-) ठीक है, मैं मानता हूं कि मैं अक्सर अपने कारखानों को शुरू करने या कुछ परीक्षण-कोड निष्पादित करने के लिए करता हूं। Btw, ' सिंगल सोर्स कोड फ़ाइल' भी एक संकेत है, कि प्रविष्टि-पिंट (डिफ़ॉल्ट रूप से मुख्य) लिंकर द्वारा प्रतिस्थापित नहीं किया गया है।
वैलेंटाइन हेनित्ज

जवाबों:


127

यह सबसे अधिक संभावना है (या इसका एक प्रकार):

 void print_fibs() 
 {
       //implementation
 }

 int ignore = (print_fibs(), 0);

 int main() {}

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

ध्यान दें कि इस तरह का कोड सुरक्षित नहीं है और इसे सामान्य रूप से बचना चाहिए। उदाहरण के लिए, std::coutऑब्जेक्ट print_fibs()निष्पादित होने पर आरंभीकृत नहीं किया जा सकता है, यदि ऐसा है तो std::coutफ़ंक्शन में क्या होगा ? हालांकि, अगर अन्य परिस्थितियों में, यह इस तरह के इनिशियलाइज़ेशन ऑर्डर पर निर्भर नहीं करता है, तो इनिशियलाइज़ेशन फ़ंक्शंस (जो C और C ++ में एक आम बात है) को कॉल करना सुरक्षित है।


3
@ नवाज़ यह शायद सटीक गारंटी का हवाला देते हुए लायक है। अनुवाद इकाई के भीतर की वस्तुओं को क्रम में शुरू करने की गारंटी है। मानक स्ट्रीम ऑब्जेक्ट्स को किसी std::ios_base::Initऑब्जेक्ट के पहले इनिशियलाइज़ेशन से पहले या उसके दौरान इनिशियलाइज़ किए जाने की गारंटी है । और <iostream>व्यवहार करने की गारंटी है "के रूप में अगर" यह std::ios_base_Initनाम स्थान पर एक वस्तु का एक उदाहरण गुंजाइश है।
जेम्स कांजे

3
@ स्टीव ३१४: यह कुछ भी वापस नहीं करता है, यही वजह है कि मैंने अल्पविराम ऑपरेटर का उपयोग किया है, यह सुनिश्चित करने के लिए कि संपूर्ण अभिव्यक्ति (print_fibs(), 0)का प्रकार है int। यहाँ ऑनलाइन डेमो है
नवाज

1
@ नवाज़ शून्य फ़ंक्शन और अल्पविराम ऑपरेटर के लिए एक विकल्प होगा bool, और चर bool fibsPrintedअगर समारोह केवल यहाँ काम करता है, तो यह शायद थोड़ा क्लीनर है। (लेकिन अंतर शायद चिंता करने के लिए पर्याप्त नहीं है।)
जेम्स कांजे

1
+1, कमाल की बात करें। इस सवाल और इस जवाब को उभारने के लिए स्टैकओवरफ्लो में शामिल होना पड़ा।
फिक्स्ड प्वाइंट

1
@ नवाज़ मुझे यकीन नहीं है कि आपकी बात क्या है। की परिभाषा std::coutपुस्तकालय में कहीं है। लेकिन जैसा कि मैंने पहले ही बताया है, मानक को पहले std::ios_base::Initऑब्जेक्ट के पहले कंस्ट्रक्टर के समाप्त होने से पहले इसे आरंभीकृत करने की आवश्यकता होती है, और इसके लिए यह आवश्यक है कि <iostream>किसी std::ios_base::Initवस्तु को नाम स्थान के दायरे में परिभाषित किया जाए। यदि अनुवाद इकाई <iostream>को ऑब्जेक्ट की परिभाषा को इनिशियलाइज़ किए जाने से पहले शामिल किया जाता है, std::coutतो निर्माण की गारंटी दी जाती है।
जेम्स कंज

18

उम्मीद है की यह मदद करेगा

class cls
{
  public:
    cls()
    {
      // Your code for fibonacci series
    }
} objCls;

int main()
{
}

इसलिए जैसे ही कक्षा का एक वैश्विक चर घोषित किया जाता है, कंस्ट्रक्टर को बुलाया जाता है और वहां आप फाइबोनैचि श्रृंखला को प्रिंट करने के लिए तर्क जोड़ते हैं।


9

हाँ यह संभव है। आपको ऑब्जेक्ट के वैश्विक उदाहरण को घोषित करने की आवश्यकता है जो ऑब्जेक्ट कंस्ट्रक्टर में फाइबोनैचि संख्याओं की गणना करता है।


6
आपको किसी ऑब्जेक्ट के वैश्विक उदाहरण को घोषित करने की आवश्यकता होती है जिसका इनिशलाइज़र फाइबोनैचि संख्याओं की गणना करता है।
बजे जेम्स कान्जे जूल

4

मैं कुछ उदाहरणों को जानता हूं जो आप बताते हैं। इसे प्राप्त करने का एक तरीका टेम्पलेट मेटाप्रोग्रामिंग का उपयोग करना है। इसका उपयोग करके आप कुछ गणना प्रक्रिया को संकलन में स्थानांतरित कर सकते हैं।

यहां आप फाइबोनैचि संख्याओं के साथ एक उदाहरण प्राप्त कर सकते हैं

यदि आप इसे एक स्थिर वर्ग निर्माता में उपयोग करते हैं और आप मुख्य फ़ंक्शन में किसी भी कोड को लिखने की आवश्यकता के बिना संख्या लिख ​​सकते हैं।

आशा है कि यह आपकी मदद करता है।


3

वैश्विक / स्थिर चर के आरंभ के दौरान चीजें हो सकती हैं। आवेदन शुरू होने पर कोड ट्रिगर किया जाएगा।


3

फ़ाइल-स्कोप ऑब्जेक्ट के लिए सभी [*] कंस्ट्रक्टर्स को पहुंचने से पहले कॉल किया जाता है main, जैसा कि नॉन-ऑब्जेक्ट फ़ाइल-स्कोप वैरिएबल के लिए सभी इनिशलाइज़र एक्सप्रेशन करते हैं।

संपादित करें: इसके अलावा, सभी फ़ाइल-स्कोप ऑब्जेक्ट्स के लिए सभी [*] विध्वंसक mainबाहर निकलने के बाद निर्माण के रिवर्स ऑर्डर में मिलते हैं । आप, सैद्धांतिक रूप से, एक वस्तु के विनाशकर्ता में अपने रिटायरमेंट प्रोग्राम को रख सकते हैं।

[*] ध्यान दें कि 'सभी' डायनामिकली लोडिंग और अनलोडिंग लाइब्रेरी के व्यवहार को नजरअंदाज करता है, जो आपके प्रोग्राम से सीधे जुड़ा नहीं था। वे तकनीकी रूप से आधार C ++ भाषा से बाहर हैं, हालाँकि।


सब ? यहां तक ​​कि dll के जो स्पष्ट रूप से बाद में लोड किए गए हैं main?
बजे जेम्स कान्जे जूल

खैर, C ++ तकनीकी रूप से गतिशील रूप से भरी हुई पुस्तकालयों को परिभाषित नहीं करता है, इसलिए शुद्ध C ++ के भीतर, मेरा कथन सही है। इसलिए, इसे शेड करें "मुख्य तक पहुंचने के बाद लोड किए गए डीएलएल / डीएसओ में निहित इनिशियलाइज़र और फ़ाइल-स्कोप ऑब्जेक्ट्स के लिए सहेजें।" इस मामले में, mainखाली है, इसलिए उन डीएलएल / डीएसओ को विध्वंसक द्वारा लोड किया जाना चाहिए, जो कि विकृत है। लेकिन, यह कंप्यूटर विज्ञान है, मुझे लगता है कि हमें "सभी" जैसे शब्दों से सावधान रहना चाहिए।
जो जेड

मैंने अपने उत्तर के ऊपर 'सभी' के लिए एक चेतावनी लिखी, और डार्टर्स के बारे में एक नोट भी जोड़ा।
जो जेड

हां, लेकिन उम्मीद है कि आएगा। प्री सी ++ 11 में डीएलएल की अनुमति देने के लिए कुछ वेजल वेंडरिंग का मतलब था, लेकिन जो व्यवहार में केवल तकनीकी रूप से इसका मतलब था, गारंटी हमेशा नहीं थी, भले ही यह सभी वास्तविक कार्यान्वयन में था, और इस पर बहुत अधिक कोड निर्भर था। C ++ 11 ने तय किया कि, कम से कम।
जेम्स कंज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.