У меня есть простая рекурсивная функция 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()
Но это ничего не изменило.:(
Теперь, что?
Обратите внимание, что в режиме отладки компилятор связывает много байтов из стека для каждой функции
, чтобы отловить ошибки переполнения буфера.
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
Редактировать: ОП Харви нашел прагму, которая включает / выключает датчики стека.
Указывает компилятору выключить проверки стека, если выключено (или -) указано ,
, или включить проверки стека {{ 1}}, если указано on (или +).
#pragma check_stack([ {on | off}] )
#pragma check_stack{+ | –}
Обновление : ну, похоже, зонды - это отдельная история.
Попробуйте следующее: / GZ (Включить проверку ошибок времени выполнения кадра стека)
Я полагаю, что для обработки исключений должно быть выделено некоторое место. Вы смотрели дизассемблер?
В Visual Studio вы можете просматривать регистр «esp», указатель стека, в окнах наблюдения (или регистров). Установите точку останова в своей функции между одним вызовом и другим, чтобы увидеть, сколько стека вы потребляете.
Для функции боли в режиме отладки в Visual Studio 2008 это 16 байтов на вызов функции.
Это также зависит от компилятора и архитектуры, которую вы используете - например, он может выравниваться до 256 байтов для более быстрого выполнения, так что каждый уровень использует 8 байтов переменной + 248 отступов.