क्या ढेर ऊपर या नीचे बढ़ता है?


88

मेरे पास c में यह कोड है:

int q = 10;
int s = 5;
int a[3];

printf("Address of a: %d\n",    (int)a);
printf("Address of a[1]: %d\n", (int)&a[1]);
printf("Address of a[2]: %d\n", (int)&a[2]);
printf("Address of q: %d\n",    (int)&q);
printf("Address of s: %d\n",    (int)&s);

आउटपुट है:

Address of a: 2293584
Address of a[1]: 2293588
Address of a[2]: 2293592
Address of q: 2293612
Address of s: 2293608

तो, मुझे लगता है कि से aकरने के लिए a[2], 4 से स्मृति पतों बढ़ जाती है प्रत्येक बाइट्स। लेकिन से qकरने के लिए s, स्मृति पतों 4 बाइट से कम हो।

मुझे आश्चर्य है 2 चीजें:

  1. क्या ढेर ऊपर या नीचे बढ़ता है? (यह मुझे इस मामले में दोनों की तरह दिखता है)
  2. क्या बीच हो a[2]और qस्मृति पतों? वहाँ एक बड़े स्मृति अंतर क्यों हैं? (20 बाइट्स)।

नोट: यह होमवर्क का सवाल नहीं है। मैं इस बात पर उत्सुक हूं कि स्टैक कैसे काम करता है। किसी भी मदद के लिए धन्यवाद।


आदेश मनमाना है। अंतर संभवत: एक मध्यवर्ती परिणाम जैसे कि & q या s को स्टोर करने के लिए है - डिसएस्पेशन को देखें और अपने लिए देखें।
टॉम लीज

मैं सहमत हूं, विधानसभा कोड पढ़ें। यदि आप इस प्रकार के प्रश्न पूछ रहे हैं तो इसे पढ़ना सीखने का समय है।
प्रति जोहानसन

विधानसभा संस्करण का जवाब देने के लिए एक सरल: stackoverflow.com/questions/664744/…
Ciro Santilli 病 assembly assembly assembly

जवाबों:


74

स्टैक का व्यवहार (बड़ा होना या बढ़ना) आवेदन बाइनरी इंटरफेस (एबीआई) और कॉल स्टैक (उर्फ सक्रियण रिकॉर्ड) पर निर्भर करता है।

अपने पूरे जीवनकाल में एक कार्यक्रम ओएस जैसे अन्य कार्यक्रमों के साथ संवाद करने के लिए बाध्य है। एबीआई निर्धारित करता है कि एक कार्यक्रम दूसरे कार्यक्रम के साथ कैसे संवाद कर सकता है।

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

उदाहरण के लिए, यदि आप MIPS ABI लेते हैं, तो कॉल स्टैक को नीचे के रूप में परिभाषित किया गया है।

आइए उस फ़ंक्शन को 'fn1' कॉल 'fn2' पर विचार करें। अब 'fn2' द्वारा देखा गया स्टैक फ्रेम निम्नानुसार है:

direction of     |                                 |
  growth of      +---------------------------------+ 
   stack         | Parameters passed by fn1(caller)|
from higher addr.|                                 |
to lower addr.   | Direction of growth is opposite |
      |          |   to direction of stack growth  |
      |          +---------------------------------+ <-- SP on entry to fn2
      |          | Return address from fn2(callee) | 
      V          +---------------------------------+ 
                 | Callee saved registers being    | 
                 |   used in the callee function   | 
                 +---------------------------------+
                 | Local variables of fn2          |
                 |(Direction of growth of frame is |
                 | same as direction of growth of  |
                 |            stack)               |
                 +---------------------------------+ 
                 | Arguments to functions called   |
                 | by fn2                          |
                 +---------------------------------+ <- Current SP after stack 
                                                        frame is allocated

अब आप देख सकते हैं कि ढेर नीचे की ओर बढ़ता है। इसलिए, यदि चर फ़ंक्शन के स्थानीय फ्रेम में आवंटित किए जाते हैं, तो चर के पते वास्तव में नीचे की ओर बढ़ते हैं। संकलनकर्ता मेमोरी आवंटन के लिए चर के आदेश पर निर्णय ले सकता है। (आपके मामले में यह या तो 'q' या 's' हो सकता है जो पहले स्टैक मेमोरी को आवंटित किया गया है। लेकिन, आमतौर पर कंपाइलर वेरिएबल की घोषणा के आदेश के अनुसार मेमोरी एलोकेशन को स्टैक करता है)।

लेकिन सरणियों के मामले में, आवंटन में केवल एकल सूचक होता है और आवंटित की जाने वाली मेमोरी को वास्तव में एकल सूचक द्वारा इंगित किया जाएगा। स्मृति को किसी सरणी के लिए सन्निहित होना चाहिए। तो, हालांकि ढेर नीचे की ओर बढ़ता है, सरणियों के लिए ढेर बढ़ता है।


5
इसके अलावा यदि आप जांचना चाहते हैं कि स्टैक ऊपर या नीचे बढ़ता है या नहीं। मुख्य कार्य में एक स्थानीय चर घोषित करें। चर का पता प्रिंट करें। मुख्य से दूसरे फ़ंक्शन को कॉल करें। फ़ंक्शन में एक स्थानीय चर घोषित करें। इसका पता प्रिंट करें। मुद्रित पतों के आधार पर हम कह सकते हैं कि स्टैक ऊपर या नीचे बढ़ता है।
गणेश गोपालसुब्रमण्यम

धन्यवाद गणेश, मेरे पास एक छोटा सा सवाल है: तीसरे चरण में, चित्र में यू आकर्षित किया गया, क्या इसका मतलब "कैलर सेव सेव रजिस्टर है जिसका उपयोग कलस्टर में किया जा रहा है" क्योंकि जब एफ 1 कॉल एफ 2, हमें एफ 1 एड्रेस स्टोर करना होगा (जो रिटर्न एड्र f2 के लिए) और f1 (calleR) रजिस्टर में f2 (कैलली) रजिस्टर नहीं हैं। सही?
CSawy

44

यह वास्तव में दो प्रश्न हैं। एक वह तरीका है जिसके बारे में स्टैक बढ़ता है जब एक फ़ंक्शन दूसरे को कॉल करता है (जब एक नया फ्रेम आवंटित किया जाता है), और दूसरा इस बारे में है कि किसी विशेष फ़ंक्शन के फ्रेम में चर कैसे रखे जाते हैं।

न तो सी मानक द्वारा निर्दिष्ट किया गया है, लेकिन उत्तर थोड़े अलग हैं:

  • जब एक नया फ्रेम आवंटित किया जाता है तो कौन सा तरीका बढ़ता है - यदि फ़ंक्शन च () कॉल फ़ंक्शन जी () है, तो क्या fफ़्रेम फ़्रेम पॉइंटर अधिक से अधिक या कम होगा g? यह किसी भी तरह से जा सकता है - यह विशेष संकलक और वास्तुकला ("कॉलिंग कन्वेंशन" देखें) पर निर्भर करता है, लेकिन यह हमेशा किसी दिए गए प्लेटफ़ॉर्म (कुछ विचित्र अपवादों के साथ, टिप्पणियों को देखें) के अनुरूप है । नीचे की ओर अधिक आम है; यह x86, PowerPC, MIPS, SPARC, EE और सेल SPUs में मामला है।
  • किसी फ़ंक्शन के स्थानीय चर को उसके स्टैक फ्रेम के अंदर कैसे रखा जाता है? यह अनिर्दिष्ट और पूरी तरह से अप्रत्याशित है; संकलक अपने स्थानीय चरों को व्यवस्थित करने के लिए स्वतंत्र है, हालांकि यह सबसे कुशल परिणाम प्राप्त करना पसंद करता है।

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

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

2
मुझे लगता है कि S / 390 (IBM zSeries) में एक ABI है जहां कॉल फ्रेम एक स्टैक पर बढ़ने के बजाय जुड़े हुए हैं।
3

2
S / 390 पर सही। एक कॉल "BALR", शाखा और लिंक रजिस्टर है। स्टैक पर धकेल दिए जाने के बजाय रिटर्न वैल्यू को रजिस्टर में डाल दिया जाता है। रिटर्न फ़ंक्शन उस रजिस्टर की सामग्री के लिए एक शाखा है। जैसे ही स्टैक गहरा हो जाता है, ढेर में जगह आवंटित की जाती है और उन्हें एक साथ जंजीर से बांध दिया जाता है। यह वह जगह है जहां "/ बिन / सच" के बराबर एमवीएस को इसका नाम मिलता है: "IEFBR14"। पहले संस्करण में एक एकल निर्देश था: "बीआर 14", जो रजिस्टर 14 की सामग्री पर आधारित था जिसमें रिटर्न एड्रेस शामिल था।
janm

1
और PIC प्रोसेसर पर कुछ संकलक पूरे कार्यक्रम विश्लेषण करते हैं और प्रत्येक फ़ंक्शन के ऑटो चर के लिए निश्चित स्थान आवंटित करते हैं; वास्तविक स्टैक छोटा है और सॉफ्टवेयर से सुलभ नहीं है; यह केवल रिटर्न एड्रेस के लिए है।
janm

13

दिशा है जो ढेर हो जाना वास्तुकला विशिष्ट है। उस ने कहा, मेरी समझ यह है कि बहुत कम हार्डवेयर आर्किटेक्चर के पास ढेर होते हैं जो बड़े होते हैं।

वह दिशा जो एक स्टैक बढ़ता है वह एक व्यक्तिगत वस्तु के लेआउट से स्वतंत्र है। इसलिए जब स्टैक बड़ा हो सकता है, तो सरणियाँ नहीं होंगी (अर्थात & सरणी [n] हमेशा रहेगी <& array [n + 1]);


4

मानक में ऐसा कुछ भी नहीं है जो यह बताता है कि स्टैक पर चीजों को कैसे व्यवस्थित किया जाता है। वास्तव में, आप एक अनुरूप संकलक का निर्माण कर सकते हैं जो स्टैक पर सन्निहित तत्वों में सरणी तत्वों को संग्रहीत नहीं करता है, बशर्ते कि यह अभी भी सरणी तत्व अंकगणित को ठीक से करने के लिए हो (ताकि यह जानता हो, उदाहरण के लिए, कि 1 था 1K दूर [0] और इसके लिए समायोजित किया जा सकता है)।

हो सकता है कि आपको अलग-अलग परिणाम मिल रहे हों, क्योंकि स्टैक "ऑब्जेक्ट्स" को जोड़ने के लिए नीचे बढ़ सकता है, सरणी एकल "ऑब्जेक्ट" है और इसमें विपरीत क्रम में आरोही तत्व हो सकते हैं। लेकिन यह उस व्यवहार पर भरोसा करने के लिए सुरक्षित नहीं है क्योंकि दिशा बदल सकती है और चर को विभिन्न कारणों से चारों ओर स्वैप किया जा सकता है, लेकिन इसके लिए सीमित है:

  • अनुकूलन।
  • संरेखण।
  • संकलक का हिस्सा प्रबंधन के व्यक्ति की सनक।

स्टैक दिशा पर मेरे उत्कृष्ट ग्रंथ के लिए यहाँ देखें :-)

आपके विशिष्ट प्रश्नों के उत्तर में:

  1. क्या ढेर ऊपर या नीचे बढ़ता है?
    यह बिल्कुल भी मायने नहीं रखता (मानक के संदर्भ में) लेकिन, जब से आपने पूछा था, यह कार्यान्वयन के आधार पर स्मृति में ऊपर या नीचे बढ़ सकता है ।
  2. [2] और q स्मृति पतों के बीच क्या होता है? वहाँ एक बड़े स्मृति अंतर क्यों हैं? (20 बाइट्स)?
    यह बिल्कुल भी मायने नहीं रखता (मानक के संदर्भ में)। संभावित कारणों के लिए ऊपर देखें।

मैंने आपको लिंक करते हुए देखा कि अधिकांश सीपीयू आर्किटेक्चर "बड़े होकर" को अपनाते हैं, क्या आप जानते हैं कि ऐसा करने का कोई फायदा है?
बैयान हुआंग

कोई विचार नहीं, वास्तव में। यह संभव है कि किसी ने सोचा कोड 0 से ऊपर की ओर जाता है, इसलिए स्टैक को हाइमैम से नीचे की ओर जाना चाहिए, ताकि अंतराफलक की संभावना को कम किया जा सके। लेकिन कुछ सीपीयू विशेष रूप से गैर-शून्य स्थानों पर कोड चलाना शुरू करते हैं ताकि ऐसा न हो। ज्यादातर चीजों के साथ, शायद यह उस तरह से किया गया था क्योंकि यह पहला तरीका था जिसे किसी ने करने के लिए सोचा था :-)
paxdiablo

@lzprgmr: आरोही क्रम में किए गए कुछ प्रकार के ढेर आवंटन होने के कुछ मामूली फायदे हैं, और यह ऐतिहासिक रूप से स्टैक और हीप के लिए एक आम संबोधित स्थान के विपरीत छोरों पर बैठने के लिए आम है। बशर्ते कि संयुक्त स्थिर + ढेर + स्टैक का उपयोग उपलब्ध स्मृति से अधिक न हो, किसी को इस बात की चिंता करने की आवश्यकता नहीं है कि प्रोग्राम कितनी स्टैक मेमोरी का उपयोग करता है।
सुपरकैट

3

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

सरणी के चारों ओर गैप कुछ प्रकार की पैडिंग हो सकती है, लेकिन यह मेरे लिए रहस्यमय है।


1
वास्तव में, मुझे पता है कि संकलक उन्हें फिर से व्यवस्थित कर सकता है, क्योंकि यह उन्हें आवंटित न करने के लिए भी स्वतंत्र है। यह सिर्फ उन्हें रजिस्टरों में डाल सकता है और किसी भी स्टैक स्पेस का उपयोग नहीं कर सकता है।
rmeador

यदि आप उनके पते का संदर्भ देते हैं तो यह उन्हें रजिस्टरों में नहीं डाल सकता है।
फ्लोरिन

अच्छी बात है, ऐसा नहीं माना जाता था। लेकिन यह अभी भी एक सबूत के रूप में है कि संकलक उन्हें फिर से व्यवस्थित कर सकता है, क्योंकि हम जानते हैं कि यह कम से कम कुछ समय में यह कर सकता है :)
rmeador

1

सबसे पहले, मेमोरी में अप्रयुक्त स्थान की इसकी 8 बाइट्स (इसके 12 नहीं, याद रखें स्टैक नीचे की ओर बढ़ता है, इसलिए जो स्थान आवंटित नहीं किया गया है वह 604 से 597 तक है)। और क्यों?। क्योंकि प्रत्येक डेटा प्रकार अपने आकार द्वारा विभाज्य पते से शुरू होने वाली मेमोरी में जगह लेता है। हमारे मामले में 3 पूर्णांकों की सरणी मेमोरी स्पेस के 12 बाइट्स लेती है और 604 12. से विभाज्य नहीं है। इसलिए यह खाली जगहों को छोड़ देता है जब तक कि यह एक मेमोरी एड्रेस का सामना नहीं करता है जो 12 से विभाज्य है, यह 596 है।

तो सरणी को आवंटित स्मृति स्थान 596 से 584 तक है। लेकिन सरणी आवंटन निरंतरता में है, इसलिए सरणी का पहला तत्व 584 पते से शुरू होता है, 596 से नहीं।


1

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

#include <stdio.h>
int f(int *x)
{
  int a;
  return x == NULL ? f(&a) : &a - x;
}

int main(void)
{
  printf("stack grows %s!\n", f(NULL) < 0 ? "down" : "up");
  return 0;
}

5
मुझे पूरा यकीन है कि यह अलग-अलग स्टैक ऑब्जेक्ट्स को इंगित करने के लिए अपरिभाषित व्यवहार है - पॉइंटर्स जो समान ऑब्जेक्ट का हिस्सा नहीं हैं, तुलनीय नहीं हैं। जाहिर है, हालांकि यह किसी भी "सामान्य" वास्तुकला पर दुर्घटनाग्रस्त नहीं होगा।
स्टीव जेसप

@SteveJessop क्या कोई तरीका है जिससे हम इसे प्रोग्रामिक रूप से स्टैक की दिशा प्राप्त करने के लिए ठीक कर सकते हैं?
xxks-kkk

@ xxks-kkk: सिद्धांत रूप में, क्योंकि एक सी कार्यान्वयन के लिए "स्टैक की दिशा" की आवश्यकता नहीं है। उदाहरण के लिए, यह कॉलिंग कन्वेंशन करने के लिए मानक का उल्लंघन नहीं करेगा जिसमें एक स्टैक ब्लॉक को अप-फ्रंट आवंटित किया जाता है, और फिर कुछ छद्म-यादृच्छिक आंतरिक मेमोरी आवंटन रूटीन का उपयोग इसके चारों ओर कूदने के लिए किया जाता है। व्यवहार में यह वास्तव में मैटजा का वर्णन करता है।
स्टीव जेसोप

0

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

[2] और q के बीच जो हुआ वह यह है कि q के स्थान के आसपास का स्थान काफी बड़ा नहीं था (यानी, १२ बाइट्स से बड़ा नहीं था) एक ३ पूर्णांक सरणी आवंटित करने के लिए।


यदि हां, तो क्यू, एस, एक आकस्मिक स्मृति क्यों नहीं है? (पूर्व: क्ष का पता: २२ ९ ३६१२ s का पता: २२ ९ ३६० of इस का पता: २२ ९ ३६०४)

मुझे

चूँकि s और a को एक साथ आबंटित नहीं किया गया था - केवल संकेतकर्ता जिन्हें सन्निहित होना चाहिए, वे ऐरे में हैं। दूसरी मेमोरी को जहां भी आवंटित किया जा सकता है।
javix

0

मेरा ढेर कम संख्या वाले पतों की ओर बढ़ा हुआ प्रतीत होता है।

अगर मैं एक अलग कंपाइलर आह्वान का उपयोग करता हूं, तो यह दूसरे कंप्यूटर पर या मेरे अपने कंप्यूटर पर भी अलग हो सकता है। ... या संकलक म्यूगट एक स्टैक का उपयोग नहीं करने का विकल्प चुनता है (सब कुछ इनलाइन करें (यदि मैं इनका पता नहीं लगाता तो कार्य और चर))।

$ cat stack.c
#include <stdio.h>

int stack(int x) {
  printf("level %d: x is at %p\n", x, (void*)&x);
  if (x == 0) return 0;
  return stack(x - 1);
}

int main(void) {
  stack(4);
  return 0;
}
$ / usr / bin / gcc -Wall -Wextra -std = c89 -pedative stack.c
$ ./a.out
स्तर 4: x 0x7fff7781190c पर है
स्तर 3: x 0x7fff778118ec पर है
स्तर 2: x 0x7fff778118cc पर है
स्तर 1: x 0x7fff778118ac पर है
स्तर 0: x 0x7fff7781188c पर है

0

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

इस मामले में, इसने स्टैक पर दो ints और तीन-इंट सरणी के लिए स्थान आवंटित किया। यह भी सरणी के बाद एक अतिरिक्त 12 बाइट्स आवंटित किया, तो यह इस तरह दिखता है:

[१२ बाइट्स]
पैडिंग (?) [१२ बाइट्स]
s [४ बाइट्स]
q [४ बाइट्स]

जो भी कारण के लिए, आपके कंपाइलर ने फैसला किया कि उसे इस फ़ंक्शन के लिए 32 बाइट्स आवंटित करने की आवश्यकता है, और संभवतः अधिक। सी प्रोग्रामर के रूप में आपके लिए यह अपारदर्शी है, आपको यह पता नहीं है कि क्यों।

यदि आप यह जानना चाहते हैं कि कोड को असेंबली भाषा में क्यों संकलित किया गया है, तो मेरा मानना ​​है कि यह MS-C कंपाइलर पर gcc और / S पर है। यदि आप उस फ़ंक्शन के शुरुआती निर्देशों को देखते हैं, तो आप पुराने स्टैक पॉइंटर को सहेजते हुए देखेंगे और फिर उसमें से 32 (या कुछ और) घटाए जाएंगे। वहां से, आप देख सकते हैं कि कैसे कोड 32-बाइट मेमोरी को ब्लॉक करता है और यह पता लगाता है कि आपका कंपाइलर क्या कर रहा है। फ़ंक्शन के अंत में, आप स्टैक पॉइंटर को पुनर्स्थापित किया जा सकता है।


0

यह आपके ऑपरेटिंग सिस्टम और आपके कंपाइलर पर निर्भर करता है।


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

3
शायद इसलिए कि एकल-वाक्य के दावे अच्छे जवाब नहीं हैं।
को ऑर्बिट

0

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

http://c0x.coding-guidelines.com/6.5.8.html

1206 यदि इंगित की गई वस्तुएं समान एग्रीगेट ऑब्जेक्ट की सदस्य हैं, तो बाद में घोषित किए गए स्ट्रक्चर मेंबर्स के लिए पॉइंटर्स स्ट्रक्चर में पहले घोषित किए गए सदस्यों की तुलना में अधिक पॉइंटर्स की तुलना करते हैं, और बड़े सबस्क्रिप्ट वैल्यू वाले एलिमेंट्स की तुलना पॉइंटर्स से ज्यादा करने वाले पॉइंटर्स की तुलना करते हैं। कम सबस्क्रिप्ट मानों के साथ सरणी।

& [0] <& a [१], हमेशा सच होना चाहिए, भले ही 'ए' आवंटित किया गया हो


अधिकांश मशीनों पर, स्टैक नीचे की ओर बढ़ता है - उन लोगों को छोड़कर जहां यह ऊपर की तरफ बढ़ता है।
जोनाथन लेफ़लर

0

यह नीचे की ओर बढ़ता है और इसकी वजह यह है कि मेमोरी में डेटा के सेट के लिए थोड़ा एंडियन बाइट ऑर्डर मानक है।

यदि आप इसे देख सकते हैं, तो यह है कि स्टैक ऊपर की ओर बढ़ता है, यदि आप 0 से मेमोरी देखते हैं, तो नीचे से ऊपर और अधिकतम से।

स्टैक के नीचे की ओर बढ़ने का कारण स्टैक या बेस पॉइंटर के परिप्रेक्ष्य से डीरेफेरेंस करने में सक्षम होना है।

याद रखें कि किसी भी प्रकार की dereferencing निम्नतम से उच्चतम पते तक बढ़ जाती है। चूंकि स्टैक नीचे की ओर बढ़ता है (उच्चतम से निम्नतम पता) यह आपको स्टैक को डायनामिक मेमोरी की तरह व्यवहार करने देता है।

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


The reason for the stack growing downward is to be able to dereference from the perspective of the stack or base pointer.बहुत अच्छा तर्क
16

0

यह आर्किटेक्चर पर निर्भर करता है। अपने स्वयं के सिस्टम की जांच करने के लिए, GeeksForGeeks से इस कोड का उपयोग करें :

// C program to check whether stack grows 
// downward or upward. 
#include<stdio.h> 

void fun(int *main_local_addr) 
{ 
    int fun_local; 
    if (main_local_addr < &fun_local) 
        printf("Stack grows upward\n"); 
    else
        printf("Stack grows downward\n"); 
} 

int main() 
{ 
    // fun's local variable 
    int main_local; 

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