2010-03-22 8 views
5

Ich habe eine einfache rekursive Funktion RCompare(), die eine komplexere Funktion Compare() aufruft, die vor dem rekursiven Aufruf zurückgibt. Jede Rekursionsebene verwendet 248 Byte Stack-Speicherplatz, der viel mehr als nötig erscheint. Hier ist die rekursive Funktion:Warum wird so viel Stapelspeicher für jede Rekursion verwendet?

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() ist ein einfacher Stapelspeicher Prüffunktion, die die Adresse eines Auto-Variable auf den Wert eine Adresse in der Nähe des Endes der in einer statischen Variablen gespeicherten Stapel vergleichen.

Es scheint mir, dass die einzigen Dinge in jeder Rekursion zum Stapel hinzugefügt sind zwei Zeigervariablen (MP ist ein Zeiger auf eine Struktur) und die Sachen, die ein Funktionsaufruf speichert, ein paar gespeicherte Register, Basiszeiger, Rückkehr Adresse, usw., alle 32-Bit (4 Byte) -Werte. Es gibt keine Möglichkeit, dass es 248 Bytes ist, oder?

ich keine nicht, wie eigentlich auf dem Stapel in einer sinnvollen Art und Weise in Visual Studio 2008.

Dank aussieht


hinzugefügt Demontage:

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    

Warum 0E4h?


Mehr Info:

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 

Sollte eine einfache alte Zeiger richtig? Die gleichen Zeiger sind in der Struktur selbst und sie sind nur normale 4-Byte-Zeiger.


Edit: Hinzugefügt:

#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() 

Aber es hat nichts ändern. :(

Nun, was

+0

Konnten Sie eine sizeof (MP) nur tun, um zu überprüfen, wie viel Speicher der Compiler denkt, dass er für den intelligenten Zeiger zuordnen sollte, zeigen Sie die Definition von MP? – Arve

+0

Es ist kein "intelligenter Zeiger". Nick D hat das Problem gefunden. – Harvey

+0

Das sieht wie eine Debug-Disassembly aus. Wird der zusätzliche Stack-Speicherplatz auch in einem Release-Build verwendet? Haben Sie versucht, die Compiler-Codegenerierungsoptionen (Projekteigenschaften -> Konfigurationseigenschaften -> C/C++ -> Codegenerierung) zu ändern? Zusätzlicher Stapelspeicher, der verwendet wird, wenn Sie eine Zeigervariable hinzufügen, klingt definitiv wie ein Pufferüberlauf-Prüfmechanismus des Compilers. – Niki

Antwort

4

Beachten Sie, dass der Compiler im Debugmodus viele Bytes aus dem Stapel bindet, bei jeder Funktion
Puffer Pufferüberlauf Fehler abfangen.

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 

Edit: der OP Harvey die Pragma gefunden Stapel Sonden ein-/auszuschalten.

check_stack

Weist den Compiler Stapel Sonden auszuschalten, wenn AUS (oder -) angegeben ist,
oder auf Stapel Sonden zu drehen, wenn ein (oder +) angegeben wird.

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

aktualisieren: gut, Sonden ist eine andere Geschichte, wie es scheint.
Versuchen Sie folgendes: /GZ (Enable Stack Frame Run-Time Error Checking)

+1

+1. abhängig von den Compiler-Optionen, könnte es sogar tun, dass in einem Release-Build – Niki

+0

Ok, das klingt wie, was vor sich geht. Gibt es ein #pragma, um das auszuschalten, wo ich es nicht will? – Harvey

+0

@Harvey, ich weiß nicht, ob es ein Pragma dafür gibt. Bei einem Release-Build sollte es entfernt werden. –

0

, die auch auf dem Compiler hängt und die Architektur Sie laufen - zB es auf 256 Bytes für eine schnellere Ausführung Ausrichten werden könnte, so dass jede Ebene die 8 Bytes der Variablen verwendet +248 padding

+0

Das ergibt keinen Sinn, denn 248 ist keine Zweierpotenz. Wenn das der Fall wäre, sollte es genau 256 pro Anruf verwenden. Es ist genau 248 pro Anruf NICHT 8 + 248. – Harvey

0

In Visual Studio können Sie das Register "esp", den Stack-Pointer, in einem Watch- (oder Register-) Fenster betrachten.Setzen Sie einen Breakpoint in Ihrer Funktion zwischen einem Call und dem nächsten, um zu sehen, wer viel Stapel, den Sie konsumieren

Bei einer Pain-Funktion im Debug-Modus in Visual Studio 2008 ist es 16 Byte pro Funktionsaufruf

+0

Ich weiß, wie viel ... 248 Bytes jede Rekursion. Aber wofür? Ich würde 40 oder 50 glauben. – Harvey

+0

Es ist 16 Bytes in einer einfachen Funktion. Es muss die MP-Variable sein – Arve

+0

Sorry "pro Funktion". Manchmal versucht mich die Rechtschreibprüfung, etwas Merkwürdiges zu schreiben. – Arve

0

Ich denke, etwas Platz für die Ausnahmebehandlung zugewiesen werden muss. Haben Sie sich die Demontage angesehen?

+0

Hinzugefügt für Sie – Harvey

Verwandte Themen