2012-02-08 3 views
8

निम्नलिखित कथन का क्या अर्थ है?कंपाइलर संकलन समय पर स्थानीय चर के पते क्यों नहीं जानता है?

स्थानीय और गतिशील रूप से आवंटित चर पतों कि संकलक द्वारा नहीं जाना जाता है जब स्रोत फ़ाइल

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

इसके अलावा, क्या आप स्थानीय चर और अन्य आवंटित किए जाने के तरीके को पढ़ने के लिए एक अच्छा लिंक प्रदान कर सकते हैं?

अग्रिम धन्यवाद!

+5

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

+0

@ बेन: यह एक पूरी तरह से अलग मुद्दा है। –

उत्तर

13

उपरोक्त उद्धरण सही है - संकलक आमतौर पर संकलन-समय पर स्थानीय चर के पते को नहीं जानता है। उस ने कहा, संकलक शायद स्टैक फ्रेम के आधार से ऑफ़सेट जानता है जिस पर एक स्थानीय चर स्थित होगा, लेकिन कॉल स्टैक की गहराई के आधार पर, जो रनटाइम पर एक अलग पते में अनुवाद कर सकता है। तो वहाँ

int Factorial(int num) { 
    int result; 
    if (num == 0) 
     result = 1; 
    else 
     result = num * Factorial(num - 1); 

    return result; 
} 

पैरामीटर num के आधार पर, इस कोड को कई पुनरावर्ती कॉल करने के अंत सकता है,: एक उदाहरण के रूप में, यह पुनरावर्ती कोड पर विचार (जो, वैसे, किसी भी अच्छे कोड का मतलब नहीं कर रहा है!) स्मृति में result की कई प्रतियां होंगी, प्रत्येक में एक अलग मूल्य होगा। नतीजतन, संकलक यह नहीं जान सकता कि वे कहां जाएंगे। हालांकि, result का प्रत्येक उदाहरण शायद प्रत्येक Factorial आमंत्रण वाले स्टैक फ्रेम के आधार से उसी राशि को ऑफ़सेट करेगा, हालांकि सिद्धांत में संकलक इस कोड को अनुकूलित करने जैसी अन्य चीजें कर सकता है ताकि result की केवल एक प्रति हो।

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

दूसरी ओर वैश्विक चर, उनके पते संकलन-समय पर ज्ञात हो सकते हैं। वे मुख्य रूप से स्थानीय लोगों से भिन्न होते हैं कि एक कार्यक्रम में हमेशा वैश्विक चर की एक प्रति होती है। निष्पादन कैसे चला जाता है इस पर निर्भर करता है कि स्थानीय चर 0 या अधिक बार मौजूद हो सकते हैं। इस तथ्य के परिणामस्वरूप कि वैश्विक की एक अनूठी प्रति है, संकलक इसके लिए एक पता हार्डकोड कर सकता है।

आगे पढ़ने के लिए के रूप में, आप कैसे एक संकलक चर बाहर रखना कर सकते हैं, तो आप Aho, लाम, सेठी, और उलमान द्वारा Compilers: Principles, Techniques, and Tools, Second Edition की एक प्रति लेने के लिए चाहते हो सकता है के एक काफी गहराई उपचार चाहते हैं तो । हालांकि इस पुस्तक में से अधिकांश पुस्तकें अन्य कंपाइलर निर्माण तकनीकों से संबंधित हैं, पुस्तक का एक बड़ा हिस्सा कोड जनरेशन और अनुकूलन को लागू करने के लिए समर्पित है जिसका उपयोग जेनरेट कोड को बेहतर बनाने के लिए किया जा सकता है।

आशा है कि इससे मदद मिलती है!

+5

* स्वचालित *, नहीं * स्थानीय * (जो 'स्थिर' हो सकता है) –

+0

@ बेनवोइग- मैं सहमत हूं। मैंने इस शब्द का उपयोग करने से परहेज किया क्योंकि अधिकांश शुरुआती प्रोग्रामर "स्वचालित" और "वैश्विक" के रूप में "स्थिर," "स्थैतिक" और "गतिशील" के विपरीत सीखते हैं क्योंकि पूर्व शब्द अधिक सामान्य होते हैं और बाद वाला आमतौर पर केवल सी/सी ++ पर लागू होता है । – templatetypedef

+0

@templatetypedef: मुझे लगता है कि मैं आपको प्राप्त करता हूं लेकिन क्या आप उपयोगकर्ता 9 66379 के जवाब में त्रुटि बता सकते हैं। उन्होंने कहा कि "संकलन समय पर, स्रोत कोड मशीन भाषा कोड में परिवर्तित हो जाता है, इसलिए कोई पता ज्ञात नहीं है"। कृपया मीठा उत्तर दें ऊपर । –

0
  1. गतिशील चर के पते अपेक्षित कारण, के लिए ज्ञात नहीं हैं क्योंकि उन्हें स्मृति पूल से गतिशील रूप से आवंटित किया जाता है।
  2. स्थानीय चर के पते ज्ञात नहीं हैं, क्योंकि वे "स्टैक" स्मृति क्षेत्र पर रहते हैं। कोड प्रवाह की रनटाइम स्थितियों के आधार पर एक प्रोग्राम की घुमावदार-अवांछित स्थगित हो सकती है।

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

void bar(); // forward declare 
void foo() 
{ 
    int i; // 'i' comes before 'j' 
    bar(); 
} 
void bar() 
{ 
    int j; // 'j' comes before 'i' 
    foo(); 
} 
int main() 
{ 
    if(...) 
    foo(); 
    else 
    bar(); 
} 

if हालत true या false हो सकता है और परिणाम केवल कार्यावधि में जाना जाता है। उस int i या int j के आधार पर स्टैक पर उपयुक्त ऑफसेट पर होगा।

+0

मुझे लगता है कि आप जवाब देते हैं कि "स्थानीय परिवर्तनीय पता संकलन समय पर ज्ञात नहीं है"। लेकिन मैंने पूछा है कि संकलक स्वयं को क्यों नहीं जानता है। –

1

मेरी राय में कथन चर या स्कॉइंग के रनटाइम पहुंच के बारे में बात नहीं कर रहा है, लेकिन कुछ subtler कहने की कोशिश कर रहा है।

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

template<int *> 
class Klass 
{ 
}; 

int x; 

//OK as it uses address of a static variable; 
Klass<&::x> x_klass; 


int main() 
{ 
    int y; 
    Klass<&y> y_klass; //NOT OK since y is local. 
} 

ऐसा लगता है टेम्पलेट्स पर कुछ अतिरिक्त बाधाओं है कि इस संकलन करने की अनुमति नहीं देते हैं:

int main() 
{ 
    static int y; 
    Klass<&y> y_klass; 
} 

हालांकि अन्य संदर्भों उस समय स्थिरांक संकलन का उपयोग किया जा सकता है &y का उपयोग करने में सक्षम।

और इसी तरह मैं इस को अमान्य घोषित किया उम्मीद थी:

static int * p; 

int main() 
{ 
    p = new int(); 
    Klass<p> p_klass; 
} 

के बाद से पी के डेटा अब गतिशील रूप से आवंटित किया जाता है (भले ही पी स्थिर होता है)।

+0

'दूसरे स्निपेट में क्लास <&y>' कानूनी है, संभवतः आपका कंपाइलर मानक को लागू नहीं कर रहा है। "ए * टेम्पलेट-तर्क * गैर-प्रकार, गैर-टेम्पलेट * टेम्पलेट-पैरामीटर * के लिए एक:" ... "एक निरंतर अभिव्यक्ति (5.1 9) होगा जो स्थिर संग्रहण अवधि और बाहरी के साथ किसी ऑब्जेक्ट का पता निर्दिष्ट करता है या आंतरिक जुड़ाव या "... (धारा 14.3.2' [temp.arg.nontype] ') यह C++ 03 से एक महत्वपूर्ण परिवर्तन है, जिसके लिए बाहरी संबंध आवश्यक है। –

+0

@BenVoigt मैं सी ++ 03 मोड में संकलित कर रहा था, मुझे लगता है। मुझे यह देखकर खुशी हो रही है कि टेम्पलेट्स पर कुछ प्रतिबंध सी ++ 11 में कम हो गए हैं। –

0

यह एक अच्छा सवाल है।

कोड निष्पादित करते समय, प्रोग्राम स्मृति में लोड किया जाता है। फिर स्थानीय चर को पता मिलता है। संकलन समय पर, स्रोत कोड को मशीन भाषा कोड में परिवर्तित किया जाता है ताकि इसे