किताबें क्यों कहती हैं, "संकलनकर्ता स्मृति में चर के लिए स्थान आवंटित करता है"?


18

किताबें क्यों कहती हैं, "संकलनकर्ता स्मृति में चर के लिए स्थान आवंटित करता है"। क्या यह निष्पादन योग्य नहीं है जो ऐसा करता है? मेरा मतलब है, उदाहरण के लिए, अगर मैं निम्नलिखित कार्यक्रम लिखता हूं,

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

और इसे संकलित करें, और एक निष्पादन योग्य प्राप्त करें (इसे program.exe होने दें), अब, यदि मैं program.exe चलाता हूं, तो यह निष्पादन योग्य फ़ाइल स्वयं चर foo के लिए कुछ स्थान आवंटित करने का आदेश देगी। नहीं होगा? कृपया समझाएं कि किताबें यह क्यों कहती रहती हैं, "कंपाइलर ऐसा करेगा ... ऐसा करें"।


11
आप कौन सी किताबों की बात कर रहे हैं?
सिरबेल

4
आपका "संबंधित प्रश्न" एक अलग प्रश्न होना चाहिए।
SShaheen


संकलक कोड उत्पन्न करता है जो ऐसा करता है या जो वे कह रहे हैं। प्रत्यक्ष या परोक्ष रूप से।
old_timer

FYI करें stackoverflow.com/questions/7372024/… और ध्यान दें कि संकलक के लिए एक संकलक स्मृति में एक कथित चर स्थान को बदलने का निर्णय ले सकता है जैसे: stackoverflow.com/questions/17774276/…
NoChance

जवाबों:


20

आप सही कह रहे हैं कि कंपाइलर ऐसा है जब आपका प्रोग्राम वास्तव में चलता है। और अगर यह एक अलग मशीन पर चलता है, तो संकलक भी अब उपलब्ध नहीं है।

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

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


हां, यही मेरा मानना ​​है। एक त्वरित जवाब के लिए धन्यवाद!
शांतिपूर्ण काउडर

12
संकलक संकलन के दौरान स्टैक पॉइंटर के लिए एक ऑफसेट द्वारा प्रतिस्थापित करके स्टैक पर चर फू के लिए आवंटित करता है। यह ढेर आवंटन से संबंधित नहीं है जो कि mallocएट द्वारा किया जाता है । अल।
सिरबेल

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

2
मुझे लगता है कि मुख्य धागे के लिए स्टैक का आकार लिंकर द्वारा आरक्षित है और फिर ओएस द्वारा संभाला जाता है। कस्टम थ्रेड्स के लिए यह ढेर आवंटन के समान है यानी कॉलर रनटाइम पर आकार को ठीक कर सकता है।
सिरबेल

4

यह चर पर निर्भर करता है। OS ढेर को आवंटित करता है, प्रोग्राम स्टैक आवंटित करेगा और कंपाइलर ग्लोबल्स / स्टैटिक्स के लिए स्थान आवंटित करेगा, अर्थात वे स्वयं एक्सई में निर्मित हैं। यदि आप 1MB वैश्विक मेमोरी आवंटित करते हैं, तो आपके exe का आकार कम से कम 1MB बढ़ जाएगा


1
यह सवाल यह नहीं है।
फिलिपिंस

2
वास्तव में यह यहां सूचीबद्ध अन्य उत्तरों की तुलना में प्रश्न के करीब है।
सिरबेल

@ जेम्स आह, यह मेरा अनुभव नहीं है। उदाहरण के लिए, int test[256][1024]; int main(){ test[0][0]=2; return 0; } इस छोटे से कार्यक्रम में 1MB आवंटित है, लेकिन केवल मुझे 1.4 Kb ऑब्जेक्ट फ़ाइल और 8.4 Kb निष्पादन योग्य बनाता है। यह राम की सही मात्रा का उपयोग करना चाहिए, यद्यपि।
गर्ट क्लैबोर्न

1
क्या यह केवल आवंटन आदेशों को ग्लोबल्स के लिए संग्रहीत नहीं किया जाना चाहिए? यदि आपने इंटिमेट या चार जैसे प्राइमेटिव्स का उपयोग करके सभी मानों को हार्डकोड किया है, तो निष्पादन योग्य का आकार निश्चित रूप से जोड़े गए चर की मात्रा से अधिक बढ़ जाएगा। जैसे कि int a1=1,a2=2,... सभी तरह से ... , a1048576=1048576;तभी आप निश्चित रूप से 1mb से कुछ बड़ा मिलेगा।
गार्ट क्लैबोर्न 22

2
यह जो कुछ भी डेटा exe के बीएसएस अनुभाग में डालता है
जेम्स

4

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

उदाहरण के लिए, जब आप लिखते हैं

int foo;

आप देख सकते हैं कि 'मैं कंपाइलर को [ आउटपुट में यह उत्पन्न करता है ] के लिए कह रहा हूं कि कंप्यूटर एक इंट के लिए पर्याप्त रैम आरक्षित करता है जिसे मैं बाद में संदर्भित कर सकता हूं। कंपाइलर संभवतः foo को ट्रैक करने के लिए एक संसाधन आईडी या कुछ तंत्र का उपयोग करेगा। मशीन कोड, आपको असेंबली लिखने के बजाय एक पाठ फ़ाइल में फू का उपयोग करने के लिए मिलता है! हुर्रे !

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


3

"संकलक स्मृति आवंटित करता है" यह कहना शाब्दिक अर्थों में तथ्यात्मक रूप से सटीक नहीं हो सकता है, लेकिन यह एक रूपक है जो सही मायनों में विचारोत्तेजक है।

वास्तव में क्या होता है कि कंपाइलर एक प्रोग्राम बनाता है जो अपनी स्वयं की मेमोरी आवंटित करता है। सिवाय इसके कि यह वह कार्यक्रम नहीं है जो मेमोरी आवंटित करता है, लेकिन ओएस।

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

लेकिन यह प्रोग्राम और कंपाइलर और सीपीयू के बारे में सोचने के लिए समझ में आता है, क्योंकि कम लोग जो कंप्यूटर के अंदर रहते हैं, इसलिए नहीं कि वे वास्तव में हैं, बल्कि इसलिए कि यह एक रूपक है जो मानव मस्तिष्क को अच्छी तरह से फिट करता है।

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


0

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

अब, अलग-अलग डायनामिक मेमोरी प्रबंधन जैसे कि मॉलॉक, नए या अपने स्वयं के मेमोरी प्रबंधन के साथ इसे भ्रमित न करें। कंपाइलर वेरिएबल स्टोरेज और एक्सेस के साथ काम कर रहे हैं लेकिन यह ध्यान नहीं देता है कि किसी अन्य फ्रेमवर्क / लाइब्रेरी में वास्तविक मूल्य का क्या मतलब है। उदाहरण के लिए:

byte* pointer = (byte*)malloc(...);

रन समय में, मॉलॉक एक मनमाना नंबर वापस कर सकता है लेकिन संकलक को परवाह नहीं है, यह सब परवाह करता है कि उस नंबर को कहां संग्रहीत किया जाए।


0

एक और अधिक सटीक वाक्यांशिंग होगी: - "कंपाइलर लोडर को चर के लिए स्थान आरक्षित करने के लिए कहता है"

C-ish वातावरण में चर के लिए तीन प्रकार के स्थान होंगे: -

  • स्थिर चर के लिए एक निश्चित ब्लॉक
  • "स्वचालित" चर के लिए एक बड़ा ब्लॉक आमतौर पर "स्टैक" के रूप में जाना जाता है। फ़ंक्शंस प्रविष्टि पर एक हिस्सा पकड़ते हैं और इसे रिटर्न पर जारी करते हैं।
  • एक बड़ा ब्लॉक जिसे "हीप" कहा जाता है, जहां प्रोग्राम मैनेज की गई मेमोरी को मॉलोक () या इसी तरह के मेमोरी मैनेजमेंट एपीआई से आवंटित किया जाता है।

एक आधुनिक ओएस हीप मेमोरी पर वास्तव में आरक्षित नहीं किया जाएगा लेकिन आवश्यकतानुसार आवंटित किया जाएगा।


0

हां, आप सही हैं, इस मामले में (किसी फ़ंक्शन में एक चर घोषित करना), आपकी पुस्तक का वाक्य संभवतः गलत है: जब आप किसी फ़ंक्शन में एक चर घोषित करते हैं, तो यह फ़ंक्शन में प्रवेश करने पर स्टैक पर आवंटित किया जाता है। वैसे भी, एक संकलक को स्थिति का अनुकूलन करना चाहिए: यदि फ़ंक्शन गैर-पुनरावर्ती है (इसके main()लिए एक अच्छा उम्मीदवार है), तो यह संकलन-समय (बीएसएस पर) "आवंटित" करना ठीक है।

(यदि आप इस बात को लेकर उत्सुक हैं कि आपके चर कहाँ रहते हैं, तो आप इसे एक गंदे तरीके से देख सकते हैं (यदि आप obj फ़ाइल संरचना की जांच नहीं करना चाहते हैं, वैसे भी, क्यों नहीं?), इसलिए आप कुछ भिन्न प्रकार के चर घोषित कर सकते हैं: स्थिर, स्टैटिक, डायनेमिक, malloc()-लोकेटेड आदि, और उनके पते प्रदर्शित करते हैं ( बेहतर पठनीयता के लिए %Xफ़ॉर्मेटर का उपयोग करें printf())। स्टैक पर रहने वाले चर बहुत अलग मेमोरी पते होंगे।)


0

रनटाइम में किया जाने वाला एकमात्र सामान स्टैक पॉइंटर को एक निश्चित राशि से टकराएगा। इसलिए कंपाइलर पहले से तय करता है:

  • फ़ंक्शन के लिए कितने स्टैक स्थान की आवश्यकता होगी।
  • स्टैक पॉइंटर से ऑफसेट प्रत्येक व्यक्तिगत चर पर स्थित होगा।

इसे एक "आवंटन" कहा जा सकता है, लेकिन निश्चित रूप से, संकलन समय के दौरान यह केवल मॉडल में होता है जो कंपाइलर के पास चल रहे प्रोग्राम का होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.