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 312 — #350<br />
✐<br />
Capítulo 11. Las refer<strong>en</strong>cias y el constructor de copia<br />
push a<br />
call f()<br />
add sp, 4<br />
mov g, register a<br />
Este código se ha simplificado para hacerlo g<strong>en</strong>érico; las expresiones b y a serán<br />
difer<strong>en</strong>tes dep<strong>en</strong>di<strong>en</strong>do de si las variables son globales (<strong>en</strong> cuyo caso serían _b y<br />
_a) o locales (el compilador las pondría <strong>en</strong> la pila). Esto también es cierto para g.<br />
La sintaxis de la llamada a f() dep<strong>en</strong>dería de su guía de estilo, y register a<br />
dep<strong>en</strong>dería de cómo su <strong>en</strong>samblador llama a los registros de la CPU. A pesar de la<br />
simplificación, la lógica del código sería la misma.<br />
Tanto <strong>en</strong> C como <strong>en</strong> <strong>C++</strong>, primero se pon<strong>en</strong> los argum<strong>en</strong>tos <strong>en</strong> la pila de derecha<br />
a izquierda, y luego se llama a la función. El código de llamada es responsable de<br />
recoger los argum<strong>en</strong>tos de la pila (lo cual explica la s<strong>en</strong>t<strong>en</strong>cia add sp, 4). Pero t<strong>en</strong>ga<br />
<strong>en</strong> cu<strong>en</strong>ta que cuando se pasan argum<strong>en</strong>tos por valor, el compilador simplem<strong>en</strong>te<br />
pone copias <strong>en</strong> la pila (conoce los tamaños de cada uno, por lo que los puede copiar).<br />
El valor de retorno de f() se coloca <strong>en</strong> un registro. Como el compilador sabe lo<br />
que se está retornando, porque la información del tipo ya está <strong>en</strong> el l<strong>en</strong>guaje, puede<br />
retornarlo colocándolo <strong>en</strong> un registro. En C, con tipos primitivos, el simple hecho de<br />
copiar los bits del valor es equival<strong>en</strong>te a copiar el objeto.<br />
Paso y retorno de objetos grandes<br />
Considere ahora los tipos definidos por el usuario. Si crea una clase y desea pasar<br />
un objeto de esa clase por valor, ¿cómo sabe el compilador lo que ti<strong>en</strong>e que hacer<br />
La información de la clase no está <strong>en</strong> el compilador, pues lo ha definido el usuario.<br />
Para investigar esto, puede empezar con una estructura simple que, claram<strong>en</strong>te,<br />
es demasiado grande para ser devuelta a través de los registros:<br />
//: C11:PassingBigStructures.cpp<br />
struct Big {<br />
char buf[100];<br />
int i;<br />
long d;<br />
} B, B2;<br />
Big bigfun(Big b) {<br />
b.i = 100; // Do something to the argum<strong>en</strong>t<br />
return b;<br />
}<br />
int main() {<br />
B2 = bigfun(B);<br />
} ///:~<br />
La conversión a código <strong>en</strong>samblador es un poco más complicada porque la mayoría<br />
de los compiladores utilizan funciones «auxiliares» (helper) <strong>en</strong> vez de inline. En<br />
la función main(), la llamada a bigfun() empieza como debe: se coloca el cont<strong>en</strong>ido<br />
de B <strong>en</strong> la pila. (Aquí podría ocurrir que algunos compiladores cargu<strong>en</strong> registros<br />
con la dirección y tamaño de Big y luego una función auxiliar se <strong>en</strong>cargue de colocar<br />
el Big <strong>en</strong> la pila).<br />
En el fragm<strong>en</strong>to de código fu<strong>en</strong>te anterior, lo único necesario antes de llamar a la<br />
312<br />
✐<br />
✐<br />
✐<br />
✐