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