2013-09-02 12 views
7

यदि मैं कथन में एक सरणी परिभाषित करता हूं तो स्मृति संकलन समय के दौरान स्मृति आवंटित की जाती है।अगर मैं कथन में एक सरणी परिभाषित करता हूं तो क्या स्मृति आवंटित हो जाती है?

if(1) 
{ 
    int a[1000]; 
} 
else 
{ 
    float b[1000]; 
} 

फिर ints + 4 * 1000 तैरता के लिए के लिए 2 * 1000 की स्मृति आवंटित हो सकते हैं?

+3

क्यों आपके कंपाइलर को खोजने के लिए उत्पन्न कोड को न देखें? –

+4

@CarlNorum शायद क्योंकि सभी को असेंबलर नहीं पता? – Kolyunya

+0

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

उत्तर

4

यह रन-टाइम में स्टैक पर आरक्षित है (एक गैर तुच्छ हालत यह सोचते हैं - आपके मामले में, संकलक सिर्फ else हिस्सा शामिल नहीं होंगे)। इसका मतलब है कि यह केवल स्कोप ब्लॉक के अंदर मौजूद है ({} के बीच)।

+1

क्या यह ** रन-टाइम ** या ** संकलन-समय ** होगा? स्थिर स्मृति आवंटन संकलन समय पर किया जाता है। –

+3

@nishantant: स्मृति की आवश्यकता संकलन-समय पर गणना की जाती है, लेकिन यह वास्तव में फ़ंक्शन की शुरुआत में रनटाइम पर आवंटित हो जाती है। – DCoder

+0

@ डीकोडर: धन्यवाद, मेरे भ्रम को हल करने के लिए। इसके अलावा मैंने अपना जवाब सही कर दिया है। –

0

रूप DCoder & धान मुझे सही है, स्मृति संकलन समय पर गणना की जाएगी लेकिन ढेर स्मृति खंड में रन-टाइम में आवंटित है, लेकिन ब्लॉक जिसमें सरणी परिभाषित किया गया है के दायरे & जीवन भर के साथ। आवंटित स्मृति का आकार आपके सिस्टम में int & float के आकार पर निर्भर करता है। this for an overview on C memory map

+0

ध्यान दें कि "सी मेमोरी मैप" जैसी कोई चीज़ नहीं है। शायद उनका मतलब "पीसी मेमोरी मैप" था लेकिन 'पी' भूल गया। – Lundin

0

if ब्लॉक में सरणी के लिए मेमोरी रन टाइम पर स्टैक पर आवंटित की जाएगी। else भाग संकलक द्वारा अनुकूलित (हटाया गया) किया जाएगा। चर के लिए चर आवंटित किए जाने के लिए, Segmentation Fault when writing to a string

1

अपने उदाहरण में, केवल इन्स के लिए स्मृति को स्टैक (1000 * आकार (int)) पर आवंटित किया जाता है।

जैसा कि आप अनुमान लगा सकते हैं, यह रन टाइम पर हो रहा है। जेनरेट कोड में कोड के संबंधित ब्लॉक में प्रवेश होने पर स्टैक पर स्थान आवंटित करने के निर्देश हैं।

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

बस घर बिंदु को चलाने के लिए, ध्यान दें कि आवंटन अलग-अलग प्रकृति के चर अलग-अलग होंगे।

if(1) 
{ 
    static int a[1000]; 
} 
else 
{ 
    static float b[1000]; 
} 

इस मामले में, इन दोनों चींटियों और फ्लोट्स के लिए स्थान आवंटित किया जाता है। इन चर के जीवनकाल कार्यक्रम है। लेकिन दृश्यता ब्लॉक गुंजाइश वे में आवंटित किए जाते हैं के भीतर है।

+0

कुछ एबीआई को यह आवश्यक है कि स्टैक पॉइंटर केवल अपवाद अवांछित कोड की सहायता के लिए प्रति फ़ंक्शन आमंत्रण में कमी हो। –

+0

अच्छा बिंदु। लेकिन वे कार्यान्वयन विनिर्देश हैं। इस तरह के मामलों के लिए, कोई भाषा के अर्थशास्त्र द्वारा जाना होगा, आपको नहीं लगता? – Ziffusion

+0

ठीक है, आप एक ऐसे प्रश्न का उत्तर नहीं दे सकते जिसका कार्यान्वयन-परिभाषित व्यवहार मानक कहता है। –

1

स्कोप

चर { } की एक जोड़ी के दायरे के अंदर घोषित ढेर पर हैं। यह किसी फ़ंक्शन की शुरुआत में घोषित चर या फ़ंक्शन के भीतर { } की किसी भी जोड़ी में लागू होता है।

int myfunc() 
{ 
    int i = 0; // On the stack, scoped: myfunc 

    printf("%i\n"); 

    if (1) 
    { 
     int j = 1; // On the stack, scope: this if statement 

     printf("%i %i\n",i,j); 
    } 

    printf("%i %i\n",i,j); // Won't work, no j 
} 

इन दिनों चर के दायरे आसपास { } तक सीमित है। मुझे याद है कि कुछ पुराने माइक्रोसॉफ्ट कंपाइलर्स ने दायरे को सीमित नहीं किया है, और अंतिम printf() के ऊपर उदाहरण में संकलन होगा।

तो यह स्मृति में कहां है?

i और j की स्मृति केवल ढेर पर आरक्षित है। यह malloc() के साथ मेमोरी आवंटन के समान नहीं है। यह महत्वपूर्ण है, क्योंकि तुलना में malloc() कॉल करना बहुत धीमा है। malloc() का उपयोग करके गतिशील रूप से आवंटित स्मृति के साथ आपको free() पर कॉल करना होगा।

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

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

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

रनटाइम क्षमता संबंधी

उपरोक्त उदाहरण मैं i और j को मान निर्दिष्ट कर रहा हूँ में। यह वास्तव में रनटाइम की एक छोटी राशि लेता है। j को केवल कथन और बाद की शाखा के मूल्यांकन के बाद 1 को सौंपा गया है जहां j घोषित किया गया है।

उदाहरण के लिए कहें कि अगर कथन का मूल्यांकन सत्य के रूप में नहीं किया गया था; उस स्थिति में j कभी सौंपा गया नहीं है। यदि j को myfunc() की शुरुआत में घोषित किया गया था तो यह हमेशा 1 का मान सौंपा जाएगा चाहे यह बयान सत्य था - समय की मामूली बर्बादी। लेकिन एक कम मामूली उदाहरण पर विचार करें जहां एक बड़ी सरणी शुरू की गई है; जो अधिक निष्पादन समय लेगा।

int myfunc() 
{ 
    int i = 0;   // On the stack, scoped: myfunc 
    int k[10000] = {0} // On the stack, scoped: myfunc. A complete waste of time 
         // when the if statement evaluates to false. 

    printf("%i\n"); 

    if (0) 
    { 
     int j = 1; // On the stack, scope: this if statement 

     // It would be better to move the declaration of k to here 
     // so that it is initialised only when the if evaluates to true. 

     printf("%i %i %i\n",i,j,k[500]); 

    } 

    printf("%i %i\n",i,j); // Won't work, no j 
} 

myfunc() के शीर्ष पर k की घोषणा रखने का मतलब है कि एक पाश 10,000 लंबे हर बार myfunc() कहा जाता है k आरंभ करने के लिए मार डाला जाता है। हालांकि यह कभी भी उपयोग नहीं किया जाता है, ताकि लूप समय की पूरी बर्बादी हो।

बेशक

, इन तुच्छ उदाहरण में compilers अनावश्यक कोड, आदि बाहर अनुकूलित करेंगे वास्तविक कोड में जहां संकलक समय से आगे अनुमान नहीं लगा सकते क्या निष्पादन प्रवाह तो हो जाएगा बातें जगह में छोड़ दिया जाता है।

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