Sunday, January 08, 2006

Librerias externas

Librerías Externas
C++ no dispone de utilidades o funciones para entrada o salida implementadas en el propio lenguaje, de modo que estas y otras muchas, como manejo de cadenas de caracteres (strings), manejo de ficheros, funciones matemáticas Etc. son implementadas en forma de librerías externas.
Una librería es un conjunto de recursos (algoritmos) prefabricados, que pueden ser utilizados por el programador para realizar determinadas operaciones.

Las declaraciones de las funciones (prototipos) utilizadas en estas librerías, junto con algunas macros y constantes predefinidas que facilitan su utilización, se agrupan en ficheros de nombres conocidos que suelen encontrarse en sitios predefinidos. Estos ficheros se suelen llamar "de cabecera", porque es tradición utilizar las primeras líneas del programa para poner las directivas #include que los incluirá en el fuente durante la fase de preprocesado.

Procesos de construcción del ejecutable

Clases de librerías
Los compiladores C++ incluyen un amplio repertorio de clases, funciones y macros que permiten realizar una amplia variedad de tareas, incluyendo entradas/salidas de bajo y alto nivel; manipulación de cadenas alfanuméricas y ficheros; control de procesos (incluyendo multiproceso); manejo de memoria; cálculos matemáticos y un largo etcétera.
Este repertorio de recursos es denominado colectivamente como "Rutinas de librería"; "Librerías de ejecución" RTL ("Runtime Librarys") o simplemente "Librerías". Puede decirse que el lenguaje aislado (tal cual) no tiene prácticamente ninguna utilidad sin la concurrencia de estas utilidades. El Estándar C++ las clasifica según su utilidad:
• Soporte del lenguaje
• Diagnóstico
• Utilidades generales
• Cadenas alfanuméricas ("Strings")
• Localización
• Contenedores
• Iteradores
• Algoritmos
• Cálculo numérico
• Entrada/Salida

Librería Estándar C++
Para poner un poco de orden, el Estándar C++ define la denominada Librería Estándar
de Pantillas, o STL ("Standar Template Library"), que debe acompañar a cada implementación del compilador que se adhiera al estándar. Es decir: la norma determina cuales son, como se llaman y como se utiliza este conjunto de algoritmos que deben acompañar (como mínimo) a cada implementación del compilador que quiera llamarse "Estándar". La última versión, ISO/IEC 14882 del año 1998, especifica que se compone de 32 ficheros de cabecera de nombres fijos y conocidos agrupados según la funcionalidad de los algoritmos.

Ficheros Funcionalidad/funciones
Parte de la STL que describe los algoritmos.
Parte de la STL relativa a contenedores tipo bitset. Set de valores booleanos.
Parte de la librería numérica de la STL relativa a los complejos.
Parte de la STL relativa a contenedores tipo deque; un tipo de colas: "Double-ended-queue" .
Parte de la librería de diagnóstico relativa al manejo de excepciones
Flujos hacia/desde ficheros.
Parte de la STL relativa a Objetos-función
Manipuladores.
Supreclases para manejo de flujos de E/S.
Contiene declaraciones adelantadas de todas las plantillas de flujos y sus typedefs estándar. Por ejemplo ostream.
Parte del a STL que contiene los algoritmos estándar de E/S.
Algoritmos estándar de flujos de entrada.
Parte de la STL relacionada con iteradores, un tipo de puntero que permite utilizar los algoritmos de la Librería con las estructuras de datos representadas por los contenedores.
Descripción de propiedades dependientes de la implementación que afectan a los tipos fundamentales.
Parte de la STL relativa a contenedores tipo list listas doblemente enlazadas
Parte de la STL relativa a la internacionalización .
Parte de la STL relativa a contenedores tipo map.
Utilidades relativas a la gestión de memoria, incluyendo asignadores y punteros inteligentes (auto_ptr).
Manejo de memoria dinámica.
Parte de la librería numérica de la STL relativa a operaciones numéricas.
Algoritmos estándar para los flujos de salida.
Parte de la STL relativa a contenedores tipo queue;colas de objetos.
Parte de la STL relativa a contenedores tipo set
Flujos hacia/desde cadenas alfanuméricas.
Parte de la STL relativa a contenedores tipo; pilas de objetos.
Parte de la STL relativa a contenedores tipo string; una generalización de las cadenas alfanuméricas para albergar cadenas de objetos.
Mecanismo de edentificación de tipos en tiempo de ejecución.
Parte de la STL que contiene elementos auxiliares como operadores y pares (pairs).
Parte de la librería numérica de la STL relativa a manejo de matrices numéricas ()
Parte de la STL relativa a los contenedores tipo vector; una generalización de las matrices unidimensionales C/C++


Es digno de mención que aunque generalmente las librerías no aportan ninguna característica al lenguaje (se supone que son utilidades auxiliares que no forman parte del lenguaje propiamente dicho), una pequeña porción de la Librería Estándar C++ si aporta características que se consideran pertenecientes a este, de forma que deben estar presentes los ficheros de cabecera correspondientes si se desea usarlas.

Componentes
Al referirnos a las librerías C++ utilizamos la terminología siguiente:
• RTL Conjunto de librerías que acompañan a un compilador ("Runtime Library"), sean o no estándar.
• Librería Estándar. Conjunto de librerías cuyo contenido está definido por el Estándar C++ (abreviadamente LE)
• Libería clásica. Parte de la Librería Estándar correspondiente al C clásico.

La calidad de un compilador C++ viene determinada en gran medida por la calidad y cantidad de su RTL; por su grado de adherencia al Estándar y por el grado de soporte que proporciona para la plataforma concreta a que se destina.
Nota: En lo que concierne a la programación para MS Windows (las referencias a la plataforma Wintel surgen de forma constante e inevitable), los compiladores Borland C++ y MS Visual C++ son quizás los más conocidos y utilizados. El primero incluye una completa librería denominada VCL (Visual Component Library. La del segundo es conocida como MFC (Microsoft Foundation Classes).
Linux dispone de su propio compilador: GNU Cpp, que comenzó siendo un compilador C y ha evolucionado a un producto que es en realidad un superconjunto de compiladores. No solo puede compilar código C y C++; también otros lenguajes como Ada o Fortran; de forma que es común referirse a ellos como GCC ("GNU Compiler Collection"). La buena noticia es que existen versiones de este compilador para plataformas Windows, de forma que incluso en este ambiente "Propietario" pueden realizarse desarrollos utilizando herramientas "Open source".

A grandes rasgos la librería Estándar C++ comprende los siguientes módulos:
• La denominada Librería Estándar de Plantillas, abreviadamente STL ("Standard Templete Library").
Librería numérica. Parte de la STL que contiene algoritmos especialmente concebidos para computación numérica. Por ejemplo, una clase valarray optimizada para matrices numéricas y una clase complex para manejo y representación estandarizada de números complejos (en realidad una plantilla con especializaciones para los tipos float, double y long double).
Utilidades. Parte de la STL dedicada a elementos auxiliares tales como adaptadores y la clase auto_ptr.
• Unas utilidades de entrada/salida de flujos, denominadas genéricamente iostreams.
• Una utilidad locale para manejo de localismos.
• Una clase string para manejo estandarizado de cadenas de caracteres. En realidad es una instanciación (especialización) de la plantilla basic_string para cadenas de caracteres.
• Un esquema para describir de modo uniforme el entorno de ejecución mediante la utilización de una clase estándar denominada numeric_limits y especialización para cada uno de los tipos de datos fundamentales.
• Utilidades para manejo de memoria.
• Soporte para utilización de juegos de caracteres y signos de diversos idiomas.
• Utilidades de diagnóstico y manejo de errores. Incluyen manejo de excepciones y la macro assert.

Funcionalidad
Si atendemos a su funcionalidad, las utilidades ofrecidas por la Librería Estándar pueden agruparse en:
• Clasificación: Clasifican caracteres ASCII, como letras, caracteres de control (no imprimibles), Mayúsculas/minúsculas etc. Se definen en la cabecera .
• Entradas/Salidas de Consola: Estas son las denominadas entrada/salida estándar. Por defecto se refieren al teclado y a la pantalla (no pueden utilizarse directamente en aplicaciones de interfaz gráfica).
• Conversión: Convierten caracteres y cadenas de caracteres desde formato alfabético a numérico de diversos tipos (float, int, long). También realizan la conversión inversa: de formatos numéricos a representaciones alfabéticas y de mayúsculas a minúsculas y viceversa.
• Diagnóstico: Son rutinas destinadas a comprobaciones; a descubrir y corregir posibles errores.
• Directorio: Rutinas para manejo de directorios y sus direcciones (path names).
• En linea (Inline): Rutinas para versiones inline de funciones. El compilador genera el código correspondiente para las versiones inline cuando se utiliza #pragma intrinsic o si se solicita optimización al compilador (optimización de tiempo de ejecución).
• Entrada/Salida. Son rutinas que proporcionan manejo de flujos y operaciones de Entrada/Salida a bajo nivel (de Sistema Operativo).
• Manipulación. Manejo de cadenas y bloques de memoria: copiar, comparar, convertir y buscar.
• Matemáticas: Para realizar cálculos matemáticos.
• De Memoria: Proporcionan asignación de memoria dinámica.
• Miscelánea. Se agrupan aquí rutinas varias, como las que posibilitan saltos (goto) no locales y las que manejan diferencias de tipo cultural o de lenguaje. Por ejemplo representación de números, de moneda, formatos de fecha y hora, clasificación de tipo alfabético, etc.
• Control de proceso. Rutinas que permiten invocar y terminar nuevos procesos desde otra rutina.
• Fecha y hora. Incluyen rutinas para conversión y manipulación de variables de medida del tiempo (fecha y hora).
• Argumentos variables. Rutinas utilizadas cuando se usan listas variables de argumentos, como en los casos de printf(), vscanf(), etc.

Utilización
La utilización de la Librería Estándar C++ requiere de dos tipos de condiciones que podríamos describir como formales y conceptuales.

En cuanto a las primeras (condiciones formales), habida cuenta que las utilidades aparecen en forma de funciones, resulta evidente que su utilización exige incluirlas en nuestro programa. Para ello se necesitan tres pasos (en realidad las exigencias son las mismas que con cualquier otra función, la diferencia estriba en la forma en que se realizan los pasos b y c):
a: Incluir en el código fuente las invocaciones a las funciones que estamos utilizando. Ejemplo:
printf("Esto es una llamada a la función \"printf\" de librería\n");
b: Incluir en el código fuente los prototipos de dichas funciones.
Puesto que los prototipos ya están incluidos en los ficheros estándar de cabecera, hay que indicar al compilador que los incluya. Esto se realiza poniendo en nuestro fuente (normalmente al principio) una directiva de preprocesado #include que señala el fichero de cabecera que se debe añadir. Por ejemplo, si el manual indica que la función printf está definida en el fichero de cabecera stdio.h ponemos en nuestro código:
#include
c: Incluir en el fuente las definiciones de las funciones utilizadas. Como alternativa se puede indicar al compilador que tales definiciones están en ficheros compilados previamente.
En este último caso se dice que las definiciones de las funciones están en librerías de las que existen dos tipos:estáticas (.LIB, .OBJ y .BPI) y dinámicas (.DLL). Toda la información que necesita el compilador está contenida en los ficheros de cabecera, por lo que las operaciones correspondientes son realizadas de forma automática; con la sola condición de que los ficheros y librerías correspondientes sean accesibles al enlazador.

No olvidar que la entidades de la Librería Estándar C++ (que no están en ficheros de cabecera .h), se han definido en un espacio de nombres denominado std, por lo que es preciso referirse a él específicamente cuando se quieran utilizar estos recursos.

Respecto a las que hemos denominado "condiciones conceptuales", damos por sentado que la utilización de algoritmos de la Librería exige conocerlos. Pero debemos advertir que existe una gran diferencia entre las rutinas de la que hemos denominado librería clásica y los recursos de la nueva Librería Estándar de Plantillas STL.

En general los algoritmos contenidos en la librería clásica realizan tareas muy sencillas bajo la forma de funciones que, con un cierto número de argumentos, realizan la tarea encomendada. A veces devolviendo un objeto (que puede ser una estructura). Su utilización exige poco más que repasar esta colección de funciones (209 en la última versión del Estándar) hasta encontrar la que mejor se ajusta a nuestras necesidades. Para esto lo mejor es recurrir a la clasificación temática ofrecida en la documentación que acompaña a los compiladores antes que a la lista alfabética de las mismas. A continuación estudiamos atentamente su prototipo y la explicación de funcionamiento que acompaña el manual (eventualmente incluso con un ejemplo) y ya estamos listos para utilizarla. En el peor de los casos suelen bastar un par de pruebas hasta que conseguimos ajustar los argumentos de forma que se consiga el resultado esperado.
Nota: A título de ejemplo, el fichero BCB5RTL.HLP, que contiene la "C Runtime Library reference", nombre con que aparece en la documentación de Borland la librería clásica, contiene dos secciones denominadas "Categorical Routines and Types Listing", una clasificación temática, y la denominada "Alphabetical Routines and Types Listing" que contiene la relación alfabética.

Como última recomendación al respecto, sobre todo si pensamos que nuestro programa tendrá una larga vida y/o pensamos portarlo a otras plataformas, aconsejaría echar un vistazo a la sección de "Compatibilidad" que acompaña a la descripción de cada función en la documentación de la mayoría de compiladores. Suele ocurrir que el compilador ofrezca muchas más funciones que las estrictamente Estándar C++, y que estas no estén claramente separadas del resto, de forma que es posible que elijamos una función que resuelve nuestro problema pero no es portable, en cuyo caso aconsejaría evitarlas dentro de lo posible.
Nota: Como ejemplo escogido al azar, la función max(), que aparece en primer lugar en la clasificación temática de la documentación Borland C (Runtime Library reference: "Categorical Routines and Types Listing"), es una función ofrecida por este compilador para el entorno Windows-32 pero no es portable a UNIX ni tampoco pertenece a los estándares C o C++.

Para todo el que no se haya asomado antes a la programación genérica, la utilización de la nueva Librería de Plantillas (STL) exige la asimilación de un nuevo paradigma; una nueva forma de pensar que, si se tiene experiencia en programación tradicional, exige incluso un "cambio de chip", ya que estas herramientas conforman un mundo enteramente nuevo y singular.
La STL ofrece un conjunto de recursos flexible, potente y altamente optimizado para resolver una gran variedad de situaciones de programación. Pero esta versatilidad y potencia tributan un precio: su alto grado de parametrización supone algo más que utilizar herramientas aisladas. Es necesario saber ensamblar entre sí los recursos disponibles, que no trabajan aisladamente y que son básicamente de tres tipos: contenedores, iteradores y algoritmos. El resultado es que el proceso de utilizar la STL es algo más complicado que la simple búsqueda de una función que resuelva nuestras necesidades; que la curva de aprendizaje es ciertamente más ardua que en el caso de la librería clásica; que los conceptos involucrados son más abstractos y requieren un conocimiento más extenso de sus fundamentos para utilizarlos. Desde luego, la descripción detallada de todos sus elementos exige un libro completo, y de hecho son muchos los que se han publicado con el objeto exclusivo de describir la STL y/o sus técnicas de uso.
En compensación las contrapartidas obtenidas justifican sin duda el esfuerzo. El programador puede concentrarse más en el problema que en los detalles de su implementación en el fuente, se incremente la productividad y se gana en claridad conceptual.

Funciones y macros
Hay que señalar que algunas funciones pueden venir implementadas de dos formas: como macro y como función. Por ejemplo, la función isalnum, contenida en . Esto significa que además de estar implementada como una función en la correspondiente librería (que se utiliza con los argumentos señalados en el manual), está definida como una macro de preprocesado en , de forma que salvo indicación contraria al compilador, el preprocesador transforma la llamada del programador en otra serie de sentencias equivalentes que utilizan los mismos argumentos. El resultado es que en el código resultante, que luego pasa al compilador y al enlazador, no existe nada parecido a una llamada a una función isalnum (técnicamente el proceso es una sustitución inline de la función de librería.
Para evitar que esto ocurra y por consiguiente que la llamada a islanum nunca llegue a producirse, basta con indefinir la correspondiente directiva. Esto se hace incluyendo al principio del código, y debajo de la línea #include , una línea de preprocesado adecuada, en este caso: #undef isalnum, con lo que el #define del preprocesador quedará sin efecto, con el resultado de que todas las invocaciones a isalnum de nuestro código serán respetadas por el preprocesador. Más tarde el enlazador cargará el código de isalnum (que extrae de la librería) con el resto de nuestro programa, y colocará en cada punto de nuestro código donde aparezca una invocación a isalnum, un salto a la dirección adecuada.

En estos casos, el resultado es el mismo en ambas modalidades: como macro (por defecto) o como función de librería. La elección de una u otra es cuestión de optimización. Para tomar una decisión es necesario comprobar y valorar dos aspectos:
• El tamaño del ejecutable que resulta en uno y otro caso. Posiblemente mayor si se utiliza la función muchas veces y se adopta la macro.
La velocidad de ejecución. Posiblemente mayor si se utiliza la función muchas veces (en bucles muy largos) y se utiliza la macro.

________________________________________
El cronometraje se puede realizar sencillamente a mano, con un cronómetro, o colocando marcadores en sitios estratégicos del programa que, utilizando el reloj del sistema, muestren los tiempos utilizados.
Ejemplo. Controlar intervalos de tiempo en el programa
#include
#include
#include
#include
void main(void) { // ==========
clock_t ini, fin;
long lg =0;
ini = clock();
for (volatile int x = 1; x < fin =" clock();" lg ="0;" ini =" clock();" y =" 1;" fin =" clock();">
void delay(int seconds) {
for(int inicio = (time(NULL) + seconds); time(NULL)!= inicio; time(NULL)){ }
}
Ejemplo de aplicación:
#include

void delay(int);

int main() { // ================
delay(10);
return 0;
}

void delay(int seconds) {
for (int inicio = time(NULL) + seconds; time(NULL) != inicio; time(NULL)) { }
}



Estrictamente hablando estas operaciones son realizadas por el preprocesador, el analizador sintáctico, el compilador o el enlazador según los casos. Nos referimos a todos estos módulos como "compilador" en un sentido genérico, pues desde un punto de vista práctico, en algunos casos (como el copilador C++Builder de Borland), solo hay que realizar una llamada al "compilador" y este se encarga de la totalidad del proceso.

"Locales" son conjuntos de datos que indican preferencias culturales. Por ejemplo: formas de representar la hora, las fechas, el "punto" decimal, etc. La utilidad locale de la Librería Estándar es la forma que tiene C++ de dar soporte a la internacionalización de los programas.

Posiblemente esta afirmación puede resultarle sorprendente a más de uno. En informática y en muchos aspectos de la vida, las leyes y normas suelen ir muy por detrás de mundo y la vida cotidianos. Es frecuente que las estandarizaciones y normativas se limiten a consagrar "oficialmente" hábitos y costumbres largamente consagrados ya por la práctica. Sin embargo, en el caso del C++ los acontecimientos se han sucedido a veces de forma contraria. En el Comité de Estandarización participan representantes de la industria (del software) junto con miembros de laboratorios de investigación y desarrollo. Teóricos de los lenguajes; estudiosos de las teorías de computación, de compiladores, Etc. que han tenido tanto o más peso que aquellos. El resultado es que en algunos casos el Estándar ha introducido y aprobado herramientas que no estaban suficientemente probadas o generalizadas en la práctica. Construcciones teóricas que ni siguiera eran soportadas por la mayoría de compiladores disponibles comercialmente. Esto, que incluso ha originado comentarios negativos por parte de algunos miembros del Comité, ha motivado que incluso algún tiempo después de publicado el Estándar, muchos compiladores no hubiesen implementado aún todas sus características.
Una librería es algo que ayuda a realizar determinadas operaciones con más facilidad que la ofrecida por los métodos implementados en el lenguaje, o que permite hacer algo que no puede hacerse con las herramientas definidas en él, pero que en rigor no forma parte del lenguaje en sí mismo. Sin embargo C++ ha sido dotado de ciertas extensiones que se han incluido en forma de librerías (denominadas "de soporte"). De forma que en cierto sentido dichas librerías si forman parte del lenguaje.
Al tratar de la construcción de un programa señalamos que en ocasiones no se desea construir un ejecutable, al menos no en el sentido tradicional del término, sino una librería, y que estas librerías son trozos de código que contienen alguna funcionalidad pre-construida que puede ser utilizada por un ejecutable. Por supuesto, las librerías contienen en su interior variables y funciones. Si, como suponemos, son librerías C++, lo más probable es que estas variables y funciones estén encapsuladas en forma de clases.
En general, el término librería se utiliza para referirse a un conjunto de módulos objeto .obj (resultados de compilación) agrupados en un solo fichero que suele tener las extensiones .LIB, .OBJ, .BPI y .DLL. Estos ficheros permiten tratar las colecciones de módulos como una sola unidad, y representan una forma muy conveniente para el manejo y desarrollo de aplicaciones grandes, además de ser un concepto muy fértil para la industria del software, ya que permiten la existencia de las librerías de los propios compiladores y de un mercado de utilidades y componentes adicionales. Son las denominadas librerías 3pp (de terceras partes), en referencia a que no son incluidas de forma estándar con los compiladores ni creadas por el programador de la aplicación.
En este sentido el software se parece a cualquier otro mercado de componentes. Además de las librerías más o menos extensas que acompañan a los compiladores, pueden adquirirse otras, que permiten añadir a nuestros programas las funcionalidades más diversas sin necesidad de ser un experto en cada área de la programación y sin necesidad de que tengamos que estar reinventando la rueda constantemente.

En lo que respecta al lenguaje C++, existen dos tipos fundamentales de librerías: Estáticas y Dinámicas, que aunque comparten el mismo nombre genérico "Librería" en realidad se refieren a conceptos distintos.

Librerías estáticas
Denominadas también librerías-objeto, son colecciones de ficheros objeto .obj (compilados) agrupados en un solo fichero de extensión .LIB y .OBJ.
Los prototipos de las funciones utilizadas en estas librerías, junto con algunas macros y constantes predefinidas que facilitan su uso, se agrupan en ficheros denominados "de cabecera", porque es tradición utilizar las primeras líneas del programa para poner las directivas #include que los incluirán en el fuente durante la fase de preprocesado.
Así pues, las librerías estáticas se componen de uno o varios ficheros .lib, .obj o .bpi junto con uno o varios ficheros de cabecera (generalmente .h).
Durante la fase de compilación, el enlazador incluye en el ejecutable los módulos correspondientes a las funciones de librería que hayan sido utilizadas en el programa, de forma que entran a formar parte del ejecutable, de ahí su nombre: Librerías enlazadas estáticamente.

Dejando aparte consideraciones de comodidad y rapidez, el resultado de utilizar una de tales librerías no se diferencia en nada al que puede obtenerse programando las funciones o clases correspondientes y compilándolas como un módulo más de nuestra aplicación.
Nota: El compilador Borland C++ dispone de una herramienta específica para la creación y manejo de librerías estáticas; el ejecutable TLIB.EXE.

Diccionario
Junto con los diversos módulos que las componen, las librerías estáticas incluyen una especie de índice o diccionario con información sobre su contenido. Este diccionario sirve para incrementar la velocidad de enlazado cuando el "Linker" debe incluir alguno de sus módulos en un ejecutable, e incluye una tabla con los nombres de todos los recursos públicos de los diversos módulos (estos símbolos deben ser distintos). Por "públicos" nos referimos a que pueden ser accedidos desde el exterior por los usuarios de la librería.

Librerías dinámicas
Otra forma de añadir funcionalidad a un ejecutable son las denominadas librerías de enlazado dinámico, generalmente conocidas como DLLs, acrónimo de su nombre en inglés ("Dynamic Linked Library"). Estas librerías se utilizan mucho en la programación para el SO Windows. Este Sistema contiene un gran número de tales librerías de terminación .DLL, aunque en realidad pueden tener cualquier otra terminación .EXE, .FON, .BPI, .DRV etc. Cualquiera que sea su terminación, de forma genérica nos referiremos a ellas como DLLs, nombre por el que son más conocidas.
Nota: La programación tradicional de aplicaciones Windows utilizando la API del Sistema es en realidad una sucesión de llamadas a este tipo de librerías externas. De hecho, este Sistema Operativo es en realidad un conjunto de tales DLLs. La mayoría de los ficheros de disco asociados con el sistema son de este tipo, y se ha llegado a afirmar que escribir una DLL es escribir una extensión del propio Windows

Diferencias: Librería Estática "versus" Dinámica
Las diferencias más relevantes de las librerías dinámicas respecto a las estáticas son fundamentalmente dos:
• Las librerías estáticas quedan incluidas en el ejecutable, mientras las dinámicas son ficheros externos, con lo que el tamaño de la aplicación (nuestro ejecutable) es mayor en el primer caso que en el segundo. Esto puede ser de capital importancia en aplicaciones muy grandes, ya que el ejecutable debe ser cargado en memoria de una sola vez.
• Las librerías dinámicas son ficheros independientes que pueden ser invocados desde cualquier ejecutable, de modo que su "funcionalidad" puede ser compartida por varios ejecutables. Esto significa que solo se necesita una copia de cada fichero de librería (DLL) en el Sistema. Esta característica constituye la razón principal de su utilización, y es también origen de algunos inconvenientes, principalmente en sistemas como Windows en los que existen centenares de ellas.

Como consecuencia de las diferencias citadas se derivan otras. Por ejemplo:
• Si se realizan modificaciones en los módulos de una librería estática, es necesario recompilar todos los ejecutables que la utilizan, mientras que esto no es necesario en el caso de una librería dinámica.
• Durante la ejecución de un ejecutable, las librerías estáticas que hubiesen intervenido en su construcción no necesitan estar presentes, en cambio las dinámicas deben estar en el mismo directorio o en el camino de búsqueda ("Path" [7]).
• Las librerías estáticas solo se utilizan en la fase de construcción del ejecutable. Las dinámicas se utilizan durante la ejecución.

Utilizar Librerías
Desde la óptica del programador C++, la utilización de Librerías comprende dos aspectos totalmente diferenciados: Su utilización y quizás la construcción de alguna de ellas si nuestras aplicaciones son medianamente grandes.
En cuanto al primer punto, es seguro que como mínimo utilice algunas de la "Librería Estándar" . En cuanto a su construcción, si se dedica a esto de programar en C++, antes o después pondrá manos a la obra. Por cierto: Hay empresas de software cuya principal actividad es precisamente fabricar y vender librerías (ya hemos indicado que el mercado de las 3pp es todo un "mundillo" dentro de la informática).
Cualquiera que sea el caso, tanto la utilización como la construcción, son diferentes según se trate de librerías estáticas o dinámicas. En las páginas que siguen se describe en detalle el caso de las segundas. Empezaremos por una descripción general de su funcionamiento, para continuar con la descripción de los pasos necesarios para construir una de tales DLLs.

________________________________________
[1] Recordemos que en C++, uno de los significados del término "estático" es algo que ha sido resuelto en tiempo de compilación.
[3] Existen utilidades que permiten compactar ("Squeeze") un ejecutable disminuyendo su tamaño como fichero, lo que puede ser de utilidad a la hora de transportarlo (por redes por ejemplo). Pero incluso en estos casos, después de cargados en memoria deben ser "expandidos" a su tamaño normal.
[6] BPI; acrónimo de Borland Package Import Library. Un tipo especial de librería dinámica de este compilador, que utiliza enlazado estático con el ejecutable que las usa.
[7] En el caso del compilador BC++, durante la construcción de un programa o librería, este "path" puede ser controlado mediante el comando de compilación -L o de enlazado /L. Más tarde durante la ejecución (runtime) este "path" depende de las variables de entorno del sistema.
En los programas para Windows caben tres opciones: Poner las librerías específicas en el mismo directorio que el ejecutable (o un subdirectorio del anterior); en nuestra opinión esto sería lo recomendado. Otra opción es ponerlas junto con el resto de librerías del sistema (Windows\System) o en un directorio particular cualquiera (no es aconsejable).

No comments: