Почему такое стековое пространство используется для каждой рекурсии?

У меня есть простая рекурсивная функция 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 () является простой функцией проверки стекового пространства, которая сравнивает адрес автоматической переменной к значению адреса около конца стека, сохраненного в статической переменной.

Мне кажется, что единственными вещами, добавленными к стеку в каждой рекурсии, являются две переменные указателя (MP является указателем на структуру), и материал, который один вызов функции хранит, несколько сохраненных регистров, указателя базы, обратного адреса, и т.д., все 32-разрядные (4-байтовые) значения. Нет никакого пути, который составляет 248 байтов, это?

Я не делаю не, как на самом деле посмотреть на стек значимым способом в Visual Studio 2008.

Спасибо


Добавленное дизассемблирование:

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?


Подробнее:

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

Должно быть простое право указателя? Те же указатели находятся в самой структуре, и они - просто нормальные 4-байтовые указатели.


Править: Добавленный:

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

Но это ничего не изменило.:(

Теперь, что?

5
задан Harvey 22 March 2010 в 10:24
поделиться

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

Редактировать: ОП Харви нашел прагму, которая включает / выключает датчики стека.

check_stack

Указывает компилятору выключить проверки стека, если выключено (или -) указано ,
, или включить проверки стека {{ 1}}, если указано on (или +).

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

Обновление : ну, похоже, зонды - это отдельная история.
Попробуйте следующее: / GZ (Включить проверку ошибок времени выполнения кадра стека)

4
ответ дан 15 December 2019 в 00:57
поделиться

Я полагаю, что для обработки исключений должно быть выделено некоторое место. Вы смотрели дизассемблер?

0
ответ дан 15 December 2019 в 00:57
поделиться

В Visual Studio вы можете просматривать регистр «esp», указатель стека, в окнах наблюдения (или регистров). Установите точку останова в своей функции между одним вызовом и другим, чтобы увидеть, сколько стека вы потребляете.

Для функции боли в режиме отладки в Visual Studio 2008 это 16 байтов на вызов функции.

0
ответ дан 15 December 2019 в 00:57
поделиться

Это также зависит от компилятора и архитектуры, которую вы используете - например, он может выравниваться до 256 байтов для более быстрого выполнения, так что каждый уровень использует 8 байтов переменной + 248 отступов.

0
ответ дан 15 December 2019 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: