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 149 — #187<br />

✐<br />

4.2. ¿Qué ti<strong>en</strong>e de malo<br />

llamamos a func() con un int como argum<strong>en</strong>to, el compilador sabrá que deberá<br />

convertir el int a float antes de pasarle el valor a la función (a esto se le llama promoción<br />

de tipos). Sin la declaración, el compilador asumiría que la función ti<strong>en</strong>e la forma<br />

func(int), no realizaría la promoción y pasaría, por lo tanto, datos incorrectos a la<br />

función.<br />

Para cada unidad de traducción, el compilador crea un archivo objeto, de ext<strong>en</strong>sión<br />

.o, .obj o algo por el estilo. Estos archivos objeto, junto con algo de código de<br />

arranque se un<strong>en</strong>s por el <strong>en</strong>lazador(linker) para crear el programa ejecutable. Todas<br />

las refer<strong>en</strong>cias externas se deb<strong>en</strong> resolver <strong>en</strong> la fase de <strong>en</strong>lazado. En archivos como<br />

CLibTest.cpp, se declaran funciones como initialize() y fetch() (o sea, se<br />

le informa al compilador qué forma ti<strong>en</strong><strong>en</strong> estas funciones), pero no se defin<strong>en</strong>. Están<br />

definidas <strong>en</strong> otro lugar, <strong>en</strong> este caso <strong>en</strong> el archivo CLib.cpp. De ese modo, las<br />

llamadas que se hac<strong>en</strong> <strong>en</strong> CLibTest.cpp a estas funciones son refer<strong>en</strong>cias externas.<br />

Cuando se un<strong>en</strong> los archivos objeto para formar el programa ejecutable, el <strong>en</strong>lazador<br />

debe, para cada refer<strong>en</strong>cia externa no resuelta, <strong>en</strong>contrar la dirección a la que hace<br />

refer<strong>en</strong>cia y reemplazar cada refer<strong>en</strong>cia externa con su dirección correspondi<strong>en</strong>te.<br />

Es importante señalar que <strong>en</strong> C, estas refer<strong>en</strong>cias externas que el <strong>en</strong>lazador busca<br />

son simples nombres de funciones, g<strong>en</strong>eralm<strong>en</strong>te precedidos por un guión bajo. De<br />

esta forma, la única tarea del <strong>en</strong>lazador es hacer corresponder el nombre de la función<br />

que se llama, con el cuerpo (definición, código) de la función del archivo objeto,<br />

<strong>en</strong> el lugar exacto de la llamada a dicha función. Si, por ejemplo, accid<strong>en</strong>talm<strong>en</strong>te<br />

hacemos una llamada a una función que el compilador interprete como func(int)<br />

y existe una definición de función para func(float) <strong>en</strong> algún archivo objeto, el<br />

<strong>en</strong>lazador verá _func <strong>en</strong> un lugar y _func <strong>en</strong> otro, por lo que p<strong>en</strong>sará que todo está<br />

bi<strong>en</strong>. En la llamada a func() se pasará un int <strong>en</strong> la pila pero el cuerpo de la función<br />

func() esperará que la pila t<strong>en</strong>ga un float. Si la función sólo lee el valor de este dato<br />

y no lo escribe, la pila no sufrirá datos. De hecho, el supuesto float leído de la pila<br />

puede t<strong>en</strong>er algo de s<strong>en</strong>tido: la función seguirá funcionando aunque sobre basura,<br />

y es por eso que los fallos originadas por esta clase de errores son muy difíciles de<br />

<strong>en</strong>contrar.<br />

4.2. ¿Qué ti<strong>en</strong>e de malo<br />

Somos seres realm<strong>en</strong>te destinados a la adaptación, incluso a las que quizá no deberíamos<br />

adaptarnos. El estilo de la librería CStash ha sido un modelo a seguir para<br />

los programadores <strong>en</strong> C durante mucho tiempo. Sin embargo, si nos ponemos a examinarla<br />

por un mom<strong>en</strong>to, nos daremos cu<strong>en</strong>ta de que utilizar esta librería puede<br />

resultar incómodo. Cuando la usamos debemos, por ejemplo, pasar la dirección de<br />

la estructura a cada función de la librería. Por eso, cuando leemos el código, los mecanismos<br />

de la librería se mezclan con el significado de las llamadas a las funciones,<br />

lo cual dificulta la comprecsión del programa.<br />

Sin embargo, uno de los mayores obstáculos al trabajar con librerías <strong>en</strong> C es el<br />

problema llamado conflicto de nombres (name clashes). C trabaja con un único espacio<br />

de nombres de funciones. Esto significa que, cuando el <strong>en</strong>lazador busca por el nombre<br />

de una función, lo hace <strong>en</strong> una única lista de nombres maestra. Además, cuando<br />

el compilador trabaja sobre una unidad de traducción, un nombre de función sólo<br />

puede hacer refer<strong>en</strong>cia a una única función con ese nombre.<br />

Supongamos que compramos dos librerías de difer<strong>en</strong>tes proveedores y que cada<br />

librería consta de una estructura que debe inicializar y destruir. Supongamos que cada<br />

proveedor ha decidido nombrar a dichas operaciones initialize() y cleanup().<br />

¿Cómo se comportaría el compilador si incluyéramos los archivos de cabecera<br />

149<br />

✐<br />

✐<br />

✐<br />

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

Saved successfully!

Ooh no, something went wrong!