El motivo es simple: los argumentos de la función son enviados a la pila por la función de llamada (que es la única que puede hacerlo porque solo tiene la información necesaria; después de todo, el objetivo de hacerlo es pasar) esa información a la función llamada). La dirección de retorno es empujada a la pila por el mecanismo de llamada de función. La función se llama después de la función de llamada ha configurado los parámetros, porque después de la llamada es la función llamada que se ejecuta, no la que llama.
Bien, entonces ahora podría argumentar que la función de llamada podría poner los parámetros más allá de la pila actualmente utilizada, y la función llamada podría entonces ajustar el puntero de la pila en consecuencia. Pero eso no funcionaría bien porque en cualquier momento podría haber una interrupción o una señal, lo que empujaría el estado actual a la pila para restaurarlo más tarde (no me sorprendería si un cambio de tarea también lo hiciera) . Pero si configura los parámetros más allá de la pila actual, esos eventos asincrónicos lo sobreescribirían, y como no puede predecir cuándo ocurrirán, no puede evitar eso (más allá de la desactivación, que puede tener otros inconvenientes o incluso ser imposible, en el caso) del cambio de tarea). Básicamente, todo lo que está más allá de la pila actual debe considerarse volátil.
También tenga en cuenta que esto es independiente de la cuestión de quién limpia los parámetros. En principio, la función llamada podría llamar a los destructores de llamadas de los argumentos, incluso si físicamente se encuentran en el marco de pila de la persona que llama.Además, muchos procesadores (incluido el x86) tienen instrucciones que automáticamente extraen espacio extra por encima de la dirección de retorno a la devolución (por ejemplo, los compiladores de Pascal generalmente lo hicieron porque en Pascal no tiene ninguna limpieza más allá de devolver la memoria, y al menos fr procesadores de la época, era más eficiente limpiar con esa instrucción del procesador (no tengo idea si eso sigue siendo cierto para los procesadores modernos). Sin embargo, C no usó ese mecanismo debido a las listas de argumentos de longitud variable: para aquellos, el mecanismo no era aplicable porque necesitarías saber en tiempo de compilación cuánto espacio extra liberar, y K & RC no requirió reenviar-declarar funciones variadas (C89 lo hace, pero pocos compiladores lo aprovechan, debido a la compatibilidad con el código anterior), por lo que no había forma de que la función de llamada supiera si limpiar los argumentos a menos que tuviera que hacer eso siempre.
Tenga en cuenta que este acuerdo ** no forma parte del estándar C++. Es específico para una CPU, compilador y/o entorno operativo individual. La situación descrita en ese artículo es típica, y es precisa para GCC/X86, pero de ninguna manera es universal. –
Es posible que no se solucione el número de parámetros y locales. ¿Cómo podría determinar la dirección de los 3 si la dirección del remitente no estaba en el medio? – Pubby
@Pubby: no tengo la respuesta, pero esa situación también está sucediendo con ** Locales de DrawSquare ** y ** Parámetros de DrawLine ** aquí. – Lazer