Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
✐<br />
✐<br />
✐<br />
“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 313 — #351<br />
✐<br />
11.3. El constructor de copia<br />
función es colocar los argum<strong>en</strong>tos <strong>en</strong> la pila. Sin embargo, <strong>en</strong> el código <strong>en</strong>samblador<br />
de PassingBigStructures.cpp se ve una acción adicional: la dirección de B2<br />
se coloca <strong>en</strong> la pila antes de hacer la llamada a la función aunque, obviam<strong>en</strong>te, no<br />
sea un argum<strong>en</strong>to. Para <strong>en</strong>t<strong>en</strong>der qué pasa, necesita <strong>en</strong>t<strong>en</strong>der las restricciones del<br />
compilador cuando llama a una función.<br />
Marco de pila para llamadas a función<br />
Cuando el compilador g<strong>en</strong>era código para llamar a una función, primero coloca<br />
<strong>en</strong> la pila todos los argum<strong>en</strong>tos y luego hace la llamada. D<strong>en</strong>tro de la función se<br />
g<strong>en</strong>era código para mover el puntero de pila hacia abajo, y así proporciona memoria<br />
para las variables locales d<strong>en</strong>tro de la función. («hacia abajo» es relativo, la máquina<br />
puede increm<strong>en</strong>tar o decrem<strong>en</strong>tar el puntero de pila al colocar un argum<strong>en</strong>to). Pero<br />
cuando se hace el CALL de <strong>en</strong>samblador para llamar a la función, la CPU coloca<br />
la dirección desde la que se realiza la llamada, y <strong>en</strong> el RETURN de <strong>en</strong>samblador se<br />
utiliza esa dirección para volver al punto desde donde se realizó la llamada. Esta<br />
dirección es sagrada, porque sin ella el programa se perdería por completo. He aquí<br />
es aspecto del marco de pila después de ejecutar CALL y poner las variables locales<br />
de la función:<br />
Argum<strong>en</strong>tos de la función<br />
Dirección de retorno<br />
Variables locales<br />
Figura 11.1: Llamada a una función<br />
El código g<strong>en</strong>erado por el resto de la función espera que la memoria t<strong>en</strong>ga esta<br />
disposición para que pueda utilizar los argum<strong>en</strong>tos y las variables locales sin tocar<br />
la dirección de retorno. Llámese a este bloque de memoria, que es todo lo que una<br />
función necesita cuando se la llama, el marco de la función (function frame).<br />
Podría parecer razonable retornar valores mediante la utilización de la pila. El<br />
compilador simplem<strong>en</strong>te los colocaría allí y la función devolvería un desplazami<strong>en</strong>to<br />
que indicara dónde empieza el valor de retorno.<br />
Re-<strong>en</strong>trada<br />
Este problema ocurre porque las funciones <strong>en</strong> C y <strong>C++</strong> pued<strong>en</strong> sufrir interrupciones;<br />
esto es, los l<strong>en</strong>guajes han de ser (y de hecho son) re-<strong>en</strong>trantes. También permit<strong>en</strong><br />
llamadas a funciones recursivas. Esto quiere decir que <strong>en</strong> cualquier punto de ejecución<br />
de un programa puede sufrir una interrupción sin que el programa se vea<br />
afectado por ello. Obviam<strong>en</strong>te la persona que escribe la rutina de servicio de interrupciones<br />
(ISR) es responsable de guardar y restaurar todos los registros que se<br />
utilic<strong>en</strong> <strong>en</strong> la ISR. Pero si la ISR necesita utilizar la pila, ha de hacerlo con seguridad.<br />
(Pi<strong>en</strong>se que una ISR es como una función normal sin argum<strong>en</strong>tos y con valor de retorno<br />
void que guarda y restaura el estado de la CPU. La ejecución de una ISR suele<br />
313<br />
✐<br />
✐<br />
✐<br />
✐