2010-03-22 15 views
5

Tengo una función recursiva simple RCompare() que llama a una función más compleja Compare() que devuelve antes de la llamada recursiva. Cada nivel de recursión utiliza 248 bytes de espacio de pila que parece mucho más de lo que debería. Aquí está la función recursiva:¿Por qué se usa tanto espacio de pila para cada recursión?

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() es un simple función de comprobación de espacio de pila que compara la dirección de una variable auto al valor de una dirección cerca del final de la pila almacenada en una variable estática.

Me parece que las únicas cosas añadidas a la pila en cada recursividad son dos variables de puntero (MP es un puntero a una estructura) y lo que almacena una llamada de función, unos pocos registros guardados, puntero base, retorno dirección, etc., todos los valores de 32 bits (4 bytes). No hay forma de que sea 248 bytes ¿verdad?

No No ¿desviar la mirada hacia la pila de una manera significativa en Visual Studio 2008.

Gracias


Agregado desmontaje:

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    

Por qué 0E4h?


Más información:

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 

debe ser un viejo y simple puntero derecho? Los mismos punteros están en la estructura misma y son solo punteros normales de 4 bytes.


Editar: Agregado:

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

pero no cambia nada. :(

Ahora lo

+0

¿Podría hacer un tamaño de (MP) solo para comprobar la cantidad de memoria que el compilador cree que debería asignar para que el puntero inteligente muestre la definición de MP? – Arve

+0

No es un "puntero inteligente". Nick D encontró el problema. – Harvey

+0

Esto parece un desensamblaje de depuración. ¿El espacio de pila adicional también se usa en una versión de lanzamiento? ¿Intentó cambiar las opciones de generación del código del compilador (propiedades del proyecto -> Propiedades de configuración -> C/C++ -> generación de código). El espacio de pila adicional que se usa cuando se agrega una variable de puntero definitivamente suena como un mecanismo de verificación de desbordamiento de búfer del compilador. – Niki

Respuesta

4

Tenga en cuenta que en modo de depuración el compilador vincula muchos bytes de la pila, en cada función,
para detectar errores de desbordamiento del búfer.

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 

Editar: la OP Harvey encontró el pragma que se enciende sondas pila/apagado.

check_stack

Indica al compilador para apagar sondas pila si fuera (o -) es especificado,
o para encender sondas pila si en (o +) se especifica.

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

actualización: así, sondas es otra historia, tal como aparece.
Prueba esto: /GZ (Enable Stack Frame Run-Time Error Checking)

+1

+1. Dependiendo de las opciones del compilador, incluso podría hacer eso en un lanzamiento de compilación – Niki

+0

Ok, eso suena como lo que puede estar pasando. ¿Hay un #pragma para desactivarlo cuando no lo quiero? – Harvey

+0

@Harvey, no sé si hay un pragma para eso. En una versión de lanzamiento, debería eliminarse. –

0

Eso también depende del compilador y la arquitectura que se está ejecutando - por ejemplo, se podría alinear a 256 bytes para una ejecución más rápida, por lo que cada nivel utiliza los 8 bytes de la variable + 248 relleno.

+0

Eso no tiene sentido porque 248 no es una potencia de dos. Si ese fuera el caso, debería usar exactamente 256 por llamada. Es exactamente 248 por llamada NO 8 + 248. – Harvey

0

En Visual Studio puede mirar el registro "esp", el puntero de la pila, en una ventana de reloj (o registro). Establezca un punto de interrupción en su función entre una llamada y la siguiente para ver a quién pila que consume.

En una función de dolor en el modo de depuración en Visual Studio 2008 es de 16 byes por llamada a la función.

+0

Sé cuánto ... 248 bytes cada recursión. ¿Pero para qué? Yo creo 40 o 50. – Harvey

+0

Tiene 16 bytes en una función simple. Tiene que ser la variable MP – Arve

+0

Lo siento "por función". A veces, el corrector ortográfico me engaña para escribir algo extraño – Arve

0

supongo que algo de espacio tiene que ser asignado para el manejo de excepciones. ¿Miraste el desmontaje?

+0

Lo agregó para tú – Harvey

Cuestiones relacionadas