13.01.2015 Views

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

SHOW MORE
SHOW LESS

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 />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!