2010-03-22 7 views
5

मैं एक साधारण पुनरावर्ती क्रिया RCompare() कहता है कि एक अधिक जटिल समारोह की तुलना() जो पुनरावर्ती कॉल करने से पहले रिटर्न दिया है। प्रत्येक रिकर्सन स्तर स्टैक स्पेस के 248 बाइट्स का उपयोग करता है जो कि ऐसा करने के तरीके से अधिक लगता है।प्रत्येक रिकर्सन के लिए इतनी स्टैक स्पेस क्यों उपयोग की जाती है?

void CMList::RCompare(MP n1) // RECURSIVE and Looping compare function 
{ 
    auto MP ne=n1->mf; 
    while(StkAvl() && Compare(n1=ne->mb)) 
    RCompare(n1); // Recursive call ! 
} 

StkAvl() एक सरल ढेर अंतरिक्ष जांच समारोह है कि ढेर एक स्थिर चर में संग्रहीत के अंत के पास एक पते के मूल्य के एक ऑटो चर का पता तुलना है: यहाँ पुनरावर्ती क्रिया है।

ऐसा लगता है कि प्रत्येक रिकर्सन में ढेर में जोड़े गए एकमात्र चीजें दो सूचक चर (एमपी एक संरचना के लिए एक सूचक है) और सामान जो एक फंक्शन कॉल स्टोर, कुछ सहेजे गए रजिस्टरों, बेस पॉइंटर, रिटर्न पता, आदि, सभी 32-बिट (4 बाइट) मान। 248 बाइट्स ऐसा कोई रास्ता नहीं है?

CMList::RCompare: 
0043E000 push  ebp 
0043E001 mov   ebp,esp 
0043E003 sub   esp,0E4h 
0043E009 push  ebx 
0043E00A push  esi 
0043E00B push  edi 
0043E00C push  ecx 
0043E00D lea   edi,[ebp-0E4h] 
0043E013 mov   ecx,39h 
0043E018 mov   eax,0CCCCCCCCh 
0043E01D rep stos dword ptr es:[edi] 
0043E01F pop   ecx 
0043E020 mov   dword ptr [ebp-8],edx 
0043E023 mov   dword ptr [ebp-14h],ecx 
0043E026 mov   eax,dword ptr [n1] 
0043E029 mov   ecx,dword ptr [eax+20h] 
0043E02C mov   dword ptr [ne],ecx 
0043E02F mov   ecx,dword ptr [this] 
0043E032 call  CMList::StkAvl (41D46Fh) 
0043E037 test  eax,eax 
0043E039 je   CMList::RCompare+63h (43E063h) 
0043E03B mov   eax,dword ptr [ne] 
0043E03E mov   ecx,dword ptr [eax+1Ch] 
0043E041 mov   dword ptr [n1],ecx 
0043E044 mov   edx,dword ptr [n1] 
0043E047 mov   ecx,dword ptr [this] 
0043E04A call  CMList::Compare (41DA05h) 
0043E04F movzx  edx,al 
0043E052 test  edx,edx 
0043E054 je   CMList::RCompare+63h (43E063h) 
0043E056 mov   edx,dword ptr [n1] 
0043E059 mov   ecx,dword ptr [this] 
0043E05C call  CMList::RCompare (41EC9Dh) 
0043E061 jmp   CMList::RCompare+2Fh (43E02Fh) 
0043E063 pop   edi 
0043E064 pop   esi 
0043E065 pop   ebx 
0043E066 add   esp,0E4h 
0043E06C cmp   ebp,esp 
0043E06E call  @ILT+5295(__RTC_CheckEsp) (41E4B4h) 
0043E073 mov   esp,ebp 
0043E075 pop   ebp 
0043E076 ret    

क्यों 0E4h:

मैं वास्तव में 2008

धन्यवाद


जोड़ा गया disassembly के दृश्य स्टूडियो में एक सार्थक तरीके से ढेर को देखने के लिए कैसे कोई नहीं है?


अधिक जानकारी:

class mch // match node structure 
{ 
public: 
    T_FSZ c1,c2; // file indexes 
    T_MSZ sz;  // match size 
    enum ntyp typ; // type of node 
    mch *mb,*mf; // pointers to next and previous match nodes 
}; 

typedef mch * MP; // for use in casting (MP) x 

एक सादे पुराने सूचक सही होना चाहिए? वही पॉइंटर्स स्वयं संरचना में हैं और वे केवल सामान्य बाइट पॉइंटर्स हैं।


संपादित करें: जोड़ा गया:

#pragma check_stack(off) 
void CMList::RCompare(MP n1) // RECURSIVE and Looping compare function 
{ 
    auto MP ne=n1->mf; 
    while(StkAvl() && Compare(n1=ne->mb)) 
    RCompare(n1); // Recursive call ! 
} // end RCompare() 
#pragma check_stack() 

लेकिन यह कुछ भी नहीं बदला। :(

अब क्या

+0

क्या आप यह जांचने के लिए एक आकार (एमपी) कर सकते हैं कि संकलक कितना स्मृति समझता है कि स्मार्ट पॉइंटर के लिए आवंटित किया जाना चाहिए एमपी की परिभाषा को दिखाएं? – Arve

+0

यह एक "स्मार्ट सूचक" नहीं है। निक डी को समस्या मिली। – Harvey

+0

यह एक डीबग disassembly की तरह दिखता है। क्या अतिरिक्त स्टैक स्पेस भी रिलीज बिल्ड में उपयोग किया जाता है? क्या आपने कंपाइलर कोड जनरेशन विकल्प (प्रोजेक्ट गुण -> कॉन्फ़िगरेशन गुण -> सी/सी ++ -> कोड जनरेशन) को बदलने का प्रयास किया था। जब आप पॉइंटर वैरिएबल जोड़ते हैं तो अतिरिक्त स्टैक स्पेस का उपयोग निश्चित रूप से कंपाइलर के कुछ बफर-ओवरफ्लो चेकिंग मैकेनिज्म की तरह लगता है। – Niki

उत्तर

4

ध्यान दें कि डीबग मोड पर कंपाइलर बफर ओवरफ्लो बग को पकड़ने के लिए प्रत्येक फ़ंक्शन,
पर स्टैक से कई बाइट बांधता है।

0043E003 sub   esp, 0E4h ; < -- bound 228 bytes 
... 
0043E00D lea   edi,[ebp-0E4h] 
0043E013 mov   ecx, 39h 
0043E018 mov   eax, 0CCCCCCCCh ; <-- sentinel 
0043E01D rep stos dword ptr es:[edi] ; <-- write sentinels 

संपादित करें: ओपी हार्वे pragma कि/बंद ढेर जांच चालू कर देता है पाया।,
निर्दिष्ट है या यदि पर (या +) निर्दिष्ट किया जाता है ढेर जांच पर चालू करने के लिए -

check_stack

बंद ढेर जांच बारी अगर बंद (या) के लिए संकलक निर्देश देता है।

#pragma check_stack([ {on | off}]) 
#pragma check_stack{+ | –} 

अद्यतन: के रूप में यह प्रतीत होता है अच्छी तरह से, जांच, एक और कहानी है।
इस प्रयास करें: /GZ (Enable Stack Frame Run-Time Error Checking)

+1

+1। कंपाइलर विकल्पों के आधार पर, यह रिलीज में भी ऐसा कर सकता है – Niki

+0

ठीक है, यह लगता है कि क्या हो रहा है। क्या वहां # प्रगामा है जो इसे बंद करने के लिए है जहां मैं इसे नहीं चाहता हूं? – Harvey

+0

@ हार्वे, मुझे नहीं पता कि इसके लिए एक प्रगति है या नहीं। एक रिलीज बिल्ड पर इसे हटाया जाना चाहिए। –

0

कि भी संकलक और वास्तुकला आप चला रहे हैं पर निर्भर करता है - जैसे यह तेजी से निष्पादन के लिए 256 बाइट्स को संरेखित किया जा सकता है, ताकि प्रत्येक स्तर चर के 8 बाइट्स का उपयोग करता है + 248 पैडिंग

+0

इसका कोई मतलब नहीं है क्योंकि 248 दो की शक्ति नहीं है। अगर ऐसा होता तो इसे प्रति कॉल 256 का उपयोग करना चाहिए। यह वास्तव में 248 प्रति कॉल 8 + 248 नहीं है। – Harvey

0

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

यह समारोह प्रति कॉल 16 बाई है।

+0

मुझे पता है कि कितना ... 248 बाइट प्रत्येक रिकर्सन। लेकिन किस लिए? मैं 40 या 50 पर विश्वास करता हूं। – Harvey

+0

यह एक सादे समारोह में 16 बाइट्स है। यह एमपी चर – Arve

+0

क्षमा करें "प्रति समारोह" है। कभी-कभी वर्तनी परीक्षक मुझे कुछ अजीब लिखने के लिए प्रेरित करता है – Arve

0

मुझे लगता है कि कुछ जगह अपवाद संचालन के लिए आवंटित किया गया है। क्या आपने डिस्सेप्लोर को देखा?

+0

इसके लिए जोड़ा गया आप – Harvey