2014-11-12 4 views
5

सी में से आप में से कई जानते हैं, स्टैक वह जगह है जहां सभी स्थानीय चर रहते हैं। पिछली आउट डेटा संरचना में पहली बार स्टैक का मतलब है कि आप केवल उस पर पहुंच सकते हैं जिसे हाल ही में उस पर धक्का दिया गया है।स्थानीय चर के लिए स्टैक का उपयोग करने के पीछे क्या विचार है?

int k = 5; 
int j = 3; 
short int i; 

if (k > j) i = 1; 

जाहिर है इस बेकार कोड जो कोई वास्तविक अर्थ नहीं है है, लेकिन मैं कुछ चारों ओर मेरे सिर लपेटो करने कोशिश कर रहा हूँ: तो निम्नलिखित कोड दिया।

संक्षिप्त int के लिए मैं घोषणा करता हूं कि मुझे लगता है कि 2 बाइट स्टैक पर आवंटित किए गए हैं। पूर्णांक कश्मीर और दोनों 4 बाइट के लिए इंट जे के लिए मैं करने के लिए अगर बयान आप पूर्णांक पॉप करने के लिए होगा के लिए इस प्रकार

---------- <- stack pointer 
int i 
---------- 
int k = 5 
---------- 
int j = 3 
---------- 

तो मान 5 और 3 के साथ आवंटित हो तो ढेर लगेगा परिस्थितियों के और जे, और यदि ऐसा है तो मैं कहाँ जाता हूं? यह सब बहुत समय लेने वाला और थकाऊ लगता है अगर ऐसा होता है कि सी स्थानीय चर करता है।

तो क्या वास्तव में यह सी कैसे करता है या मैं इसे सब खत्म कर रहा हूं?

+0

वास्तव में स्टैक पर वस्तुओं का आपका लेआउट गलत है, क्योंकि मैं छोटा हूं, int नहीं। और एक ढेर स्मृति में नीचे की ओर बढ़ता है, ऊपर की ओर नहीं और स्थानीय चर को स्टैक पर, विपरीत क्रम में रखा जाता है। अनियंत्रित, स्थानीय ढेर पर कोई भी मूल्य ढेर पॉइंटर से ऑफसेट होने के बजाय पॉप नहीं किया जाता है, इसलिए 'के' परिणामों का जिक्र करते हुए "स्पैम शब्द (कुछ रजिस्टर) में स्पॉट [ऑफसेट से के)" के समान होता है। 'परिवर्तनीय। और 'i' को "आधा शब्द एसपी [ऑफसेट से i] के रूप में सेट किया गया है (रजिस्टर के निचले हिस्से में जिसमें के + जे का परिणाम होता है) सामान्य रूप से आप स्टैक को विभाजन के साथ लंबी श्रृंखला के रूप में सोच सकते हैं – user3629249

उत्तर

4

आप इसे कभी-कभी थोड़ा-सा कर रहे हैं।

हां, स्थानीय (auto) चर आमतौर पर एक ढेर पर संग्रहीत होते हैं। हालांकि, जब वे पढ़ते हैं तो वे ढेर से नहीं निकलते हैं; उन्हें स्टैक पॉइंटर से ऑफसेट द्वारा संदर्भित किया जाता है।

x = y + z; 

जहां x, y, और z में से प्रत्येक के ढेर पर आवंटित किए जाते हैं:

निम्नलिखित कोड है।जब संकलक बराबर मशीन कोड उत्पन्न करता है, यह एक एक दिया रजिस्टर से ऑफसेट द्वारा प्रत्येक चर का उल्लेख होगा, एक तरह से पसंद है:

mov -8(%ebp), %eax 
add -12(%ebp), %eax 
mov %eax, -4(%ebp) 

86 आर्किटेक्चर पर, %ebpफ्रेम सूचक है; ढेर फ्रेम में टूट गया है, जहां प्रत्येक फ्रेम में फ़ंक्शन पैरामीटर (यदि कोई हो), वापसी पता (यानी, फ़ंक्शन कॉल के बाद निर्देश का पता), और स्थानीय चर (यदि कोई हो) है। उन प्रणालियों पर जिन्हें मैं परिचित हूं, स्टैक 0 की ओर "नीचे की तरफ" बढ़ता है, और स्थानीय चर फ्रेम सूचक (निचले पते) "नीचे" नकारात्मक ऑफसेट संग्रहीत होते हैं। उपरोक्त कोड मानता है कि x-4(%ebp) पर है, y -8(%ebp) पर है, और z-12(%ebp) पर है।

फ़ंक्शन लौटने पर सबकुछ से बाहर हो जाएगा, लेकिन इससे पहले नहीं।

संपादित

कृपया ध्यान दें कि कोई भी इस की सी भाषा परिभाषा द्वारा अनिवार्य है। भाषा को सभी पर रनटाइम स्टैक के उपयोग की आवश्यकता नहीं है (हालांकि एक कंपाइलर बिना किसी कार्यान्वयन के लिए एक कुतिया होगा)। यह केवल auto चर के जीवनकाल को उनके समापन के अंत तक उनके घोषणापत्र के अंत तक परिभाषित करता है। एक ढेर इतना आसान बनाता है, लेकिन इसकी आवश्यकता नहीं है।


1. ठीक है, ढेर और फ्रेम पॉइंटर्स नए मानों पर सेट किए जाएंगे; डेटा वहां रहेगा, लेकिन यह स्मृति अब किसी और चीज़ के उपयोग के लिए उपलब्ध है।

7

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

+0

वास्तव में, यदि आप देखते हैं सी फ़ंक्शन के डिस्सेप्लर पर, आपको स्थानीय चर के लिए पुश और पॉप नहीं मिलेगा, आपको बेस स्टैक पॉइंटर से निरंतर ऑफसेट मिलेगा - वेरिएबल्स यादृच्छिक एक्सेस मेमोरी में होने के अलावा एक बहुत ही अनुमानित जगह पर हैं। ओपी के उदाहरण में 'के' लोड करने के लिए निर्देश, उदाहरण के लिए,' mov eax, [ebp-4] 'जैसा दिखता है - स्टैक पॉइंटर स्वयं, फ़ंक्शन के भीतर परिवर्तनीय होने के कारण, वास्तव में स्थानीय लोगों के लिए भी उपयोग नहीं किया जाता है। –

+0

ऐसा लगता है कि आपके साथ कई स्रोत असहमत हैं, यहां उनमें से एक है: http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html नोट "वह स्टैक एक" फिलो "(पहले, आखिरी बार) डेटा संरचना है, जो है सीपीयू द्वारा काफी बारीकी से प्रबंधित और अनुकूलित। " मुझे यह इंगित करना चाहिए कि मैं यह नहीं कह रहा हूं कि यह हार्डवेयर स्टैक पॉइंटर का उपयोग करता है लेकिन यह वास्तव में एक FILO स्टैक – Anthony

+1

है जेनरेट कोड 'gcc -c foo.c'' को देखने में मदद कर सकता है, फिर 'objdump -d foo.o '(वैकल्पिक रूप से '-एम इंटेल' को objdump में जोड़ना यदि आप मेरे जैसे हैं और एटी एंड टी सिंटैक्स से नफरत करते हैं) और आप देख सकते हैं कि वास्तव में क्या उत्पन्न होता है। हालांकि मुझे लगता है कि अगर आप असेंबली भाषा नहीं पढ़ सकते हैं तो इससे मदद नहीं मिलती है ... लेकिन इससे कम यह है कि कॉल निर्देश स्टैक पर रिटर्न एड्रेस को धक्का देता है, फिर फ़ंक्शन स्थानीय लोगों के लिए मेमोरी का उपयोग करता है, फिर लौटने से वह सब कुछ फिर से बंद हो जाता है। तो यह एक शुद्ध ढेर के बजाय सरणी के ढेर की तरह थोड़े है। –

0

स्टैक के शीर्ष पर, इंटेल प्रोसेसर पर और कई अन्य लोगों को सीपीयू रजिस्टर में संग्रहीत पते से संदर्भित किया जाता है, इसे एसपी कहते हैं जिसे बेस पॉइंटर में कॉपी किया गया है, इसे बीपी कहते हैं; कई मशीन निर्देश बाइट ऑफसेट के साथ संयुक्त बीपी से बना पता पता अभिव्यक्ति की अनुमति देते हैं। इसलिए, आपके उदाहरण में मैं 0 ऑफसेट कर दूंगा, जे ऑफसेट -2 होगा और के ऑफसेट -6 होगा।

यदि पते -6 (बीपी) और -4 (बीपी) की सामग्री की तुलना में बस हल किया जाएगा। वास्तविक ऑफ़सेट मान कार्यान्वयन से कार्यान्वयन में भिन्न हो सकते हैं; लेकिन, यह सामान्य विचार है ...

4

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

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

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