2009-08-28 16 views
11

ऐसा प्रतीत नहीं होता है कि असेंबली में इसे लागू करना बहुत कठिन होगा।नेस्टेड फ़ंक्शंस सी मानक द्वारा समर्थित क्यों नहीं हैं?

जीसीसी में उनके उपयोग को सक्षम करने के लिए एक ध्वज (-फनेस्टेड-फ़ंक्शंस) भी है।

+2

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

+1

@ मैट: टिप्पणी के बजाए उत्तर की तरह लगता है – AnthonyWJones

+0

मैट बॉल: मेरा सवाल वास्तव में मानक-परिभाषित निकाय ने ऐसी सुविधा को छोड़ना क्यों चुना। जीसीसी का मेरा संदर्भ अधिक उदाहरण था "यह किया जा सकता है तो ऐसा क्यों नहीं है"। – des4maisons

उत्तर

11

यह पता चला है कि वे वास्तव में ठीक से लागू करने के लिए आसान नहीं हैं।

क्या किसी आंतरिक फ़ंक्शन में स्कोप के चर के उपयोग की आवश्यकता होनी चाहिए? यदि नहीं, तो इसे घोंसला करने में कोई बात नहीं है; बस इसे स्थैतिक बनाएं (अनुवाद इकाई में दृश्यता को सीमित करने के लिए) और एक टिप्पणी जोड़ें "यह एक सहायक काम है जो केवल myfunc()" द्वारा उपयोग किया जाता है।

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

+0

लॉल @ आपके पहले 2 पैराग्राफ - वे मेरे – Claudiu

+0

के समान हैं आप केवल नेस्टेड फ़ंक्शन का पता लेने से मना कर सकते हैं, है ना? – caf

+6

नेस्टेड फ़ंक्शंस में अप-स्तरीय परिवर्तनीय पहुंच को कार्यान्वित करने के दो सबसे आम तरीके "स्थैतिक लिंक" हैं, जहां प्रत्येक फ़ंक्शन में अपने शब्दावली माता-पिता के स्टैक फ्रेम में पॉइंटर होता है, और "डिस्प्ले" होता है, जिसमें ऐसे पॉइंटर्स की एक सरणी होती है । यह मूल रूप से एक निश्चित सरणी बनाम एक लिंक्ड सूची बनाम है। आपको पूर्णतया बंद होने की आवश्यकता नहीं है जब तक कि आप अपने माता-पिता के बाहर निकलने के बाद किसी आंतरिक फ़ंक्शन को कॉल करने की अनुमति नहीं देना चाहते हैं (उदाहरण के लिए पास्कल, उसे अनुमति नहीं देता है)। http://en.wikipedia.org/wiki/Call_stack#Lexically_nested_routines –

2

ANSI सी 20 वर्षों के लिए स्थापित किया गया है। शायद 1 9 83 और 1 9 8 9 के बीच समिति ने उस समय संकलक प्रौद्योगिकी की स्थिति के प्रकाश में चर्चा की हो, लेकिन अगर उन्होंने तर्क दिया कि उनका तर्क मंद और दूर के अतीत में खो गया है।

+1

बहुत यकीन है कि आप वहां वर्षों का मतलब है ... हे। –

+1

... या आपने एक अतिरिक्त 0. –

+0

जोड़ा गया। । –

9

मैं BDFL (गुइडो van Rossum) से quote something करना चाहते हैं:

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

जोर मेरा है।

मेरा मानना ​​है कि वह पायथन में नेस्टेड स्कोप का जिक्र कर रहा था (और जैसा कि डेविड टिप्पणियों में बताता है, यह 1 99 3 से था, और पायथन अब पूरी तरह से घोंसले के कार्यों का समर्थन करता है) - लेकिन मुझे लगता है कि कथन अभी भी लागू होता है।

इसका दूसरा भाग closures हो सकता था।

आप इस सी-तरह कोड की तरह एक समारोह है, तो:

(*int()) foo() { 
    int x = 5; 
    int bar() { 
     x = x + 1; 
     return x; 
    } 
    return &bar; 
} 

आप किसी प्रकार की एक कॉलबैक में bar उपयोग करते हैं, क्या एक्स के साथ क्या होता है? यह कई नई, उच्च स्तरीय भाषाओं में अच्छी तरह से परिभाषित है, लेकिन AFAIK को x सी में ट्रैक करने के लिए कोई अच्छी तरह से परिभाषित तरीका नहीं है - bar हर बार वापसी 6, या bar पर लगातार कॉल करने के लिए मूल्यों को बढ़ाना? इससे संभावित रूप से सी की अपेक्षाकृत सरल परिभाषा की जटिलता की एक पूरी नई परत जोड़ा जा सकता था।

+3

संभवतः, यदि आप कॉलबैक के रूप में बार का उपयोग कर रहे थे, तो आप उस फ़ंक्शन के बाद स्थानीय चर (बार) के पते का उपयोग करेंगे। यह सच होगा यदि बार एक int (कहना) है, तो चाहिए अपरिभाषित हो। – des4maisons

+0

लेकिन पहली ऑर्डर फ़ंक्शंस के साथ अधिकांश भाषाएं (उदाहरण के लिए पायथन और लुआ) क्लासिक क्लोजर शैली में इस व्यवहार को परिभाषित करती हैं - 'बार' 5,6,7 लौटाएगी, ... नेस्टेड फ़ंक्शंस लगभग * आवश्यकताएं * फ़ंक्शंस प्रथम आदेश वी होना alues। –

+2

यह सच है ... हम्म, मैंने इसे नहीं माना था। लेकिन सी और पायथन "स्थानीय" सरणी (या लिस्ट, पायथन में) लौटने पर अलग-अलग चीजें करते हैं। सी आपको स्मृति को ढेर करने के लिए एक सूचक वापस कर देगा जो अब अच्छी तरह परिभाषित नहीं है; पायथन आपको एक पूरी नई सूची वापस कर देगा। तो वे अलग-अलग प्रतिमान हैं, और मुझे यकीन नहीं है कि वे तुलनीय हैं। – des4maisons

3

सदस्यों को स्ट्रक्चर में कार्यों को जोड़ने में भी मुश्किल नहीं होगी लेकिन वे मानक में भी नहीं हैं।

विशेषताएं सोली के आधार पर सी मानक में शामिल नहीं हैं चाहे वे कार्यान्वित करने में आसान हों या नहीं। यह उस समय के बिंदु सहित कई अन्य कारकों का संयोजन है जिसमें मानक लिखा गया था और फिर सामान्य/व्यावहारिक क्या था।

+0

हम्म ... एक निश्चित "यह क्यों है" जवाब नहीं मिला है, शायद आप सही हैं। मैं अभी भी चाहता हूं कि एक अच्छा कारण था। – des4maisons

+2

दुर्भाग्यवश, कारण संभवत: 'सुविधा के लिए पर्याप्त लोगों की देखभाल नहीं' के रूप में सरल है। सी मानकों की प्रक्रिया आम तौर पर मौजूदा अभ्यास को संहिताबद्ध करने में से एक है। चूंकि कुछ कंपाइलर्स ने कभी ऐसा किया है, इसे मानक में होने के लिए कभी भी धक्का नहीं दिया गया है। यह देखते हुए कि यह सी में ज्यादा मदद नहीं करता है (क्योंकि आपके पास क्लोजर या नेस्टेड ग्लोबल स्कोपिंग जैसी चीजें नहीं हैं जो घोंसले के कार्यों को वास्तव में दिलचस्प बनाती हैं), यह अभी तक कभी नहीं मिला है। –

+0

मानकीकरण मौजूदा अभ्यास को मानकीकृत करने के लिए चार्टर के लिए था। उन्होंने उससे भी अधिक किया, लेकिन नेस्टेड फ़ंक्शंस को दूर तक जाने के रूप में माना जाता। बीसीपीएल और बीएलआईएसएस और असेंबलरों के बराबर - आपको 70 के दशक और सी की परिभाषा को सिस्टम भाषा के रूप में जाना होगा। – AProgrammer

5

संभावित समस्याओं के लिए C FAQ 20.24 और the GCC manual देखें:

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

यह वास्तव में सी मानक के कुछ अन्य समस्याग्रस्त भागों से अधिक गंभीर नहीं है, इसलिए मैं कहेंगे कारणों ज्यादातर ऐतिहासिक हैं (C99 नहीं वास्तव में कि कश्मीर & से अलग है आर सी सुविधा के लिहाज से) ।

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

0

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

5

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

+0

स्टैक-आवंटित चर होने पर समस्या क्या है यदि हम उन्हें बंद कर देते हैं? – Lazer

+0

इसके अलावा, यह बेवकूफ लग सकता है, लेकिन आपको नेस्टेड कार्यों के साथ बंद करने की आवश्यकता क्यों है? नेस्टेड कार्यों के बारे में इतना खास क्या है? धन्यवाद! – Lazer

+1

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

-3

से आपका काफी प्रश्न है और इसका उत्तर एक ट्यूटोलॉजी है ... क्यों? इसलिये!

मैं यह भी पूछ सकता हूं कि सी क्यों नहीं है, ओह, मुझे डिफ़ॉल्ट रूप से मूल्य के आधार पर संदर्भ द्वारा पास किया गया है। या कुछ भी जो उसके पास नहीं है।

यदि आप नेस्टेड फ़ंक्शंस चाहते हैं, तो अच्छा है! उन भाषाओं का पता लगाएं और उनका उपयोग करें जो उनका समर्थन करते हैं।

1

मैं डेव वांडर्वियों से असहमत हूं।

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

क्या होगा यदि आपको इस सहायक समारोह के लिए एक सहायक कार्य की आवश्यकता है? क्या आप एक टिप्पणी जोड़ देंगे "यह केवल मायफनक द्वारा उपयोग किए जाने वाले पहले सहायक फ़ंक्शन के लिए एक सहायक कार्य है"? नेमस्पेस को पूरी तरह प्रदूषित किए बिना आप उन सभी कार्यों के लिए आवश्यक नामों को कहां से लेते हैं?

कोड कितना भ्रमित हो सकता है?

लेकिन निश्चित रूप से, बंद करने से निपटने के तरीके में समस्या है, यानी एक ऐसे फ़ंक्शन पर एक पॉइंटर लौटा रहा है जिसमें फ़ंक्शन में परिभाषित चरों तक पहुंच है।

1

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

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

इसलिए, मैंने इस प्रोग्रामिंग को "नेस्टेड फ़ंक्शंस" के बजाय "सेमी-ग्लोबल वेरिएबल्स" का निर्माण करना शुरू कर दिया, और कोड पर काम करने वाले अन्य लोगों को बताया कि वैश्विक चर से एकमात्र चीज एक अर्ध-ग्लोबल वैरिएबल थी, और कृपया और न बनाएं। अगर मैं कर सकता, तो मैं इसे भाषा से प्रतिबंधित कर दूंगा। अफसोस की बात है, कंपाइलर के लिए ऐसा कोई विकल्प नहीं था ...

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