Introducción al lenguaje C. Complilación y enlazado

Elementos de un programa C. Tipos básicos de datos. E/S básica. Sentencias de control. Funciones. Asignación dinámica de memoria. Ficheros. Ficheros indexados: la interfase Btrieve. Compilación y enlazado. Biblioteca de funciones de Turbo C

  • Enviado por: Juan
  • Idioma: castellano
  • País: España España
  • 14 páginas
publicidad

12

Compilación y enlazado

Introducción

Turbo C proporciona un entorno integrado de desarrollo de aplicaciones (IDE: Integrated Development Environment) que permite, mediante un sencillo sistema de menús, editar, compilar, enlazar, ejecutar y depurar un programa sin abandonar dicho entorno. Pero, además, puede usarse cualquier editor de texto para crear nuestros programas, y realizar la compilación y enlazado desde la línea de órdenes del DOS. En este capítulo se muestra cómo hacerlo.

Modelos de memoria

Cuando un programa C se carga en memoria debemos distinguir en él cuatro partes:

  • Código del programa.

  • Datos estáticos: Datos con tiempo de vida global a los que se asigna memoria en los segmentos de datos del programa.

  • Datos dinámicos: Datos a los que se les asigna memoria en tiempo de ejecución, a medida que se necesita. Esta memoria no se toma de los segmentos de datos, sino de una zona aparte denominada montón (heap).

  • Datos automáticos: Datos locales. Se les asigna memoria en la pila cuando se ejecuta el bloque del programa en que están definidos.

En C hay 6 formas posibles de organizar estas partes del programa en la memoria. Estos 6 modelos de memoria se denominan:

  • Diminuto (Tiny)

  • Pequeño (Small)

  • Mediano (Medium)

  • Compacto (Compact)

  • Grande (Large)

  • Enorme (Huge)

Modelo Diminuto (Tiny)

Tanto el código como los datos ocupan el mismo segmento, que es único. Por tanto, un programa compilado y enlazado bajo este modelo no puede superar los 64 Kb. Estos programas no asignan memoria para su pila, sino que utilizan la del DOS. Por ello, en el enlazado se muestra la advertencia Warning: no stack. Los registros CS, DS, ES y SS no cambian durante el programa y tienen todos el mismo valor. Los programas .EXE generados así pueden convertirse a .COM mediante la utilidad del DOS EXE2BIN, cuya sintaxis es

exe2bin prog.exe prog.com

Modelo Pequeño (Small)

Es el modelo usado por defecto. Puede contener 64 Kb de código y otros 64 Kb para todos los datos. Durante la ejecución del programa los valores de CS, DS, ES y SS no cambian, pero a diferencia con el modelo diminuto, CS y DS contienen valores diferentes.

Modelo Mediano (Medium)

Todos los datos se almacenan en el mismo segmento, por lo que no pueden superar los 64 Kb. Por el contrario, el código puede ocupar hasta 1 Mb (16 segmentos de 64 Kb).

Modelo Compacto (Compact)

El código está limitado a un segmento de 64 Kb, pero los datos pueden ocupar 1 Mb. De los 16 segmentos de datos, sólo uno (64 Kb) puede ser utilizado para los datos estáticos.

Modelo Grande (Large)

Tanto el código como los datos pueden ocupar 1 Mb cada uno, pero los datos estáticos están limitados a 64 Kb.

Modelo Enorme (Huge)

Mantiene las capacidades del modelo Grande, pero sin la limitación de 64 Kb para datos estáticos.

Para decidir qué modelo de memoria se debe utilizar, hay que tener en cuenta los siguientes aspectos:

  • Cantidad de código y datos del programa.

  • Los programas generados con los modelos de memoria más pequeños se ejecutan más rápidamente, por lo que hay que elegir el modelo de memoria más pequeño posible.

  • Cualquier archivo .OBJ resultante de compilar un módulo simple no puede sobrepasar los 64 Kb de código ni los 64 Kb de datos, puesto que cada módulo compilado ha de encajar en un segmento de memoria. Cuando se utilizan los modelos Mediano, Grande y Enorme los programas pueden llegar hasta 1 Mb, pero a base de módulos no superiores a 64 Kb. Si el código de algún módulo supera este límite, se genera un mensaje

Too much code defined in file

Si los datos estáticos superan los 64 Kb, se genera el mensaje

To much global data defined in file

En ambos casos hay que dividir los módulos en ficheros más pequeños.

El compilador TCC

El programa TCC.EXE es el compilador independiente del entorno. Mediante TCC podemos obtener directamente programas .EXE, o bien archivos .OBJ para ser enlazados posteriormente. La sintaxis de TCC es

tcc <opciones> fichero(s)

La siguiente tabla muestra las opciones posibles

OPCIÓN

SIGNIFICADO

-A

-a

-a-

-B

-C

-c

-Dnom

-Dnom=cad

-d

-enom

-f

-f-

-f87

-G

-gN

-Iruta

-iN

-jN

-K

-K-

-Lruta

-M

-mx

-N

-nruta

-O

-onom

-p

-p-

-r

-r-

-S

-Unom

-w

-w-

-wxxx

-wxxx-

-Y

-y

-Z

-z

-1

-1-

-2

Sólo reconoce palabras clave ANSI.

Alinea los datos en frontera de palabra.

Alinea los datos en frontera de byte.

Acepta código ensamblador y llama a MASM para procesarlo.

Acepta comentarios anidados.

Compila a .OBJ (sin enlazar).

Define el nombre (nom) de una constante, como si fuera una directiva #define dentro del programa, para ser usada con la directiva #if defined.

Hace lo mismo que una directiva #define nom cad.

Asigna la misma posición de memoria a cadenas idénticas del código fuente.

Establece el nombre del fichero .EXE resultante.

Usa la emulación de coma flotante.

Pone en off la emulación de coma flotante.

Usa el coprocesador matemático sin generar código de emulación.

Optimiza el código para velocidad en lugar de para tamaño.

Detiene la compilación tras N advertencias (Warnings).

Establece la ruta para los archivos #include.

Especifica la longitud de los identificadores.

Detiene la compilación tras N errores.

Establece por defecto para el tipo char el modificador unsigned.

Establece por defecto para el tipo char el modificador signed.

Establece la ruta para las bibliotecas.

Crea archivo de mapa de memoria.

Establece un modelo de memoria según el carácter x (Pág. 198).

Comprueba el desbordamiento de pila.

Establece el directorio para los ficheros de salida (.OBJ y .EXE).

Optimiza el código para tamaño en lugar de para velocidad.

Especifica el nombre del archivo .OBJ, sin llamar al enlazador.

Usa el convenio de llamada de Pascal.

Usa el convenio de llamada de C.

Permite a las variables register usar los registros SI y DI.

Pone a off la opción anterior.

Genera como salida un fichero fuente en ensamblador (.ASM).

Deja sin definir las definiciones previas dadas por la opción -D.

Muestra mensajes de advertencia.

No muestra mensajes de advertencia.

Pone en on las advertencias de error xxx, código de 3 letras que especifica el tipo (ver Guía del Programador).

Pone en off las advertencias de error xxx.

Fabrica la pila estándar.

Incluye números de línea en el código.

Activa la optimización de registro. El programa recuerda el contenido de los registros y, si es posible, vuelve a utilizarlos en lugar de volver a cargar el valor de memoria.

Especifica los nombres de los segmentos (Guía de Referencia).

Genera instrucciones 80186/80286.

No genera instrucciones 80186/80286.

Genera instrucciones 80286 en modo protegido.

Por ejemplo, la orden

tcc -Ic:\tc\include -mc -eprog fich1 fich2 fich3.obj

contiene las opciones

  • -I indica que los archivos #include se buscarán en c:\tc\include.

  • -m especifica el modelo de memoria a usar. En este caso, -mc selecciona el modelo Compacto.

  • -e especifica que el fichero resultante de la compilación será PROG.EXE.

La orden anterior compila los archivos FICH1.C y FICH2.C y obtiene los archivos FICH1.OBJ y FICH2.OBJ correspondientes que enlaza después con FICH3.OBJ para obtener PROG.EXE.

En los procesos de compilación hay opciones que se repiten en la mayoría de las ocasiones y que debemos teclear cada vez. Para evitar esto puede crearse un archivo de configuración denominado TURBOC.CFG con las opciones más comunes. TCC busca siempre este archivo en el directorio actual, y si no lo encuentra lo busca en el directorio en que está ubicado TCC, generalmente el directotio c:\tc\bin. Por ejemplo, el archivo TURBOC.CFG puede tener las siguientes líneas:

-Ic:\tc\include

-Lc:\tc\lib

-ms

-G

con lo que TCC buscará los archivos #include en c:\tc\include (-I), las bibliotecas en c:\tc\lib (-L), seleccionará el modelo Compacto de memoria (-mc) y optimizará el código para velocidad (-G).

El enlazador TLINK

Cuando ejecutamos TCC sin la opción -c, los archivos son compilados y enlazados para obtener el ejecutable. Pero puede usarse TCC de forma que sólo compile, sin enlazar, usando la opción -c. Por ejemplo

tcc -Ic:\tc\include -mc -G -c fuentes

compila los archivos de la lista fuentes a .OBJ sin enlazarlos después. Posteriormente debe usarse el enlazador independiente TLINK, cuya sintaxis es

tlink <opciones> archivos_OBJ, archivo_EXE, archivo_MAP, bibliotecas

Las opciones de TLINK se muestran a continuación:

OPCIÓN

SIGNIFICADO

/c

/d

/e

/i

/l

/m

/n

/s

/t

/v

/x

/3

Los símbolos PUBLIC y EXTERN distinguen mayúsculas y minúsculas.

Mostrar una advertencia si hay símbolos duplicados en las bibliotecas.

No usar palabras clave extendidas.

Inicializar todos los segmentos

Incluir los números de línea de la fuente para la depuración. Es necesario usar la opción -y con TCC.

Incluir los símbolos públicos en el archivo de mapa.

Ignorar las bibliotecas por defecto.

Incluir un mapa detallado de los segmentos en el archivo de mapa.

Crear un archivo .COM (sólo para el modelo Diminuto de memoria).

Incluir toda la información completa de depuración.

No crear un archivo de mapa.

Usar procesamiento completo de 32 bits.

archivos_OBJ es el nombre de todos los archivos .OBJ que se quieren enlazar (separados por blancos). El primero de ellos ha de ser un módulo de iniciación de Turbo C. Estos módulos están normalmente en el directorio c:\tc\lib y hay uno para cada modelo de memoria. El nombre de estos archivos es C0x.OBJ, siendo x un carácter que especifica el modelo de memoria usado. Los valores posibles de x se especifican en la tabla siguiente:

x

MODELO

t

Diminuto (Tiny)

s

Pequeño (Small)

m

Mediano (Medium)

c

Compacto (Compact)

l

Grande (Large)

h

Enorme (Huge)

Así, el archivo c:\tc\lib\c0l.obj es el módulo de iniciación de Turbo C para el modelo Grande de memoria.

archivo_EXE es el nombre del programa ejecutable a generar. Si no se especifica, se asume el nombre del primer archivo .OBJ que no sea un módulo de iniciación de Turbo C.

archivo_MAP es el nombre de un archivo que contiene un mapa de memoria del programa. Tiene extensión .MAP y, si no se especifica, asume como nombre el del archivo .EXE. El fichero de mapa no se crea TLINK lleva la opción /x.

bibliotecas es una lista de bibliotecas a enlazar. Aparte de las bibliotecas de usuario, debe enlazarse el correspondiente archivo de biblioteca estándar. Existe uno para cada modelo de memoria y se almacenan en c:\tc\lib. El nombre de estos archivos es Cx.LIB, siendo x un carácter de la tabla anterior que especifica el modelo de memoria. Además de estas bibliotecas, si el programa usa operaciones en coma flotante debe enlazarse el archivo FP87.LIB si se dispone de coprocesador matemático. En caso contrario se enlazará el archivo EMU.LIB. Ambos archivos se encuentran, normalmente, en c:\tc\lib. Por último están los archivos que almacenan las rutinas matemáticas, que se llaman MATHx.LIB, siendo x el carácter que identifica el modelo de memoria.

Con las siguientes órdenes se compila el archivo PROG.C (que usa operaciones en coma flotante) a PROG.OBJ y posteriormente se enlaza a PROG.EXE sin generar fichero de mapa. Se usa el modelo Pequeño de memoria.

tcc -Ic:\tc\include -ms -G -c prog

tlink /x c:\tc\lib\c0s prog, , , c:\tc\lib\emu c:\tc\lib\cs

El enlazador TLINK también permite la sintaxis

tlink @fichero_respuesta

siendo fichero_respuesta un archivo de texto con todas las órdenes. Por ejemplo, un fichero de respuesta puede ser

/x +

c:\tc\lib\c0s prog1 prog2, +

prog3, +

, +

c:\tc\lib\cs

donde los signos + indican continuación en la línea siguiente.

El bibliotecario TLIB

Una biblioteca es un archivo .LIB que almacena módulos .OBJ. Un programa puede hacer llamadas a funciones que han sido compilados individualmente e incluidos en una biblioteca. Para ello se enlaza el programa con la biblioteca y en este proceso de enlazado sólo se tomarán de la biblioteca los módulos objeto que se usen. El bibliotecario de Turbo C se llama TLIB y la sintaxis de su uso es

tlib nombre_biblioteca [op]modulo_OBJ

donde nombre_biblioteca es el nombre del archivo .LIB, y modulo_OBJ es el módulo sobre el que se realiza la operación indicada por op, que puede ser una de las siguientes:

OPERADOR

ACCIÓN

+

-

*

-+ ó +-

-* ó *-

Añade un módulo a la biblioteca

Elimina un módulo de la biblioteca

Extrae un archivo .OBJ de la biblioteca

Reemplaza el módulo especificado con una nueva copia

Extrae el módulo especificado y lo elimina de la biblioteca

Por ejemplo, la orden

tlib mibiblio +funcion1 -funcion2

añade el archivo FUNCION1.OBJ a la biblioteca MIBIBLIO.LIB y elimina de la misma el archivo FUNCION2.OBJ.

Análogamente a TLINK, TLIB admite un fichero de respuestas, en cuyo caso la sintaxis es

tlib nombre_biblioteca @fichero_respuestas

La utilidad MAKE

El programa MAKE automatiza la recompilación de programas formados por varios módulos. Básicamente, MAKE comprueba si alguno de los módulos de que está compuesto el programa ha sido modificado y realiza las acciones de compilación, enlazado u otras necesarias para la actualización del programa. Para ello, MAKE parte de un archivo de construcción, que está compuesto por sentencias como las siguientes:

archivo_objetivo1: lista_de_archivos_dependientes

secuencia de órdenes

archivo_objetivo2: lista_de_archivos_dependientes

secuencia de órdenes

...

...

archivo_objetivoN: lista_de_archivos_dependientes

secuencia de órdenes

La línea que contiene archivo_objetivo debe empezar en la primera columna, y la secuencia de órdenes debe comenzar por una tabulador. Entre cada bloque debe haber, al menos, una línea en blanco.

Un archivo objetivo es aquél que se obtiene a partir de los archivos dependientes. Por ejemplo, PROG.C es un archivo dependiente de PROG.OBJ pues para crear PROG.OBJ hay que compilar PROG.C.

Por ejemplo, si el programa PROG está formado por los módulos MOD1 y MOD2, el archivo de construcción de MAKE podría tener el siguiente aspecto:

PROG.EXE: MOD1.OBJ MOD2.OBJ

tlink /x c0s mod1 mod2, prog,, cs

MOD1.OBJ: MOD1.C

tcc -Ic:\tc\include -G -c -ms mod1

MOD2.OBJ: MOD2.C

tcc -Ic:\tc\include -G -c -ms mod2

El programa MAKE busca un archivo de construcción llamado MAKEFILE. Basta entonces con teclear desde la línea de órdenes del DOS

make

Si el archivo tiene un nombre diferente, digamos PROG.MAK, debe usarse la opción -f como sigue:

make -fPROG.MAK

MAKE tiene varias opciones disponibles, que se pueden consultar mediante la opción -? (make -?).

Un ejemplo sencillo

Vamos a aplicar lo explicado en los apartados del capítulo con un ejemplo sencillo. En primer lugar, supondremos que nuestro directorio de trabajo es C:\TRABAJO y que en él tenemos el archivo TURBOC.CFG siguiente:

-Ic:\tc\include

-Lc:\tc\lib

-G

y el archivo EJEMPLO.C siguiente:

/* Programa EJEMPLO.C */

#include <stdio.h>

#inlcude <conio.h>

float suma (float, float);

float producto (float, float);

void main (void)

{

float a, b;

clrscr ();

printf ("Teclea dos números: ");

scanf ("%f %f", &a, &b);

printf ("\nSuma: %f", suma (a, b));

printf ("\nProducto: %f", producto (a, b));

}

float suma (float x, float y);

{

return x + y;

}

float (producto (float x, float y)

{

return x * y;

}

Para obtener el programa EJEMPLO.EXE basta con hacer:

C:\TRABAJO> tcc -ms ejemplo

Turbo C++ Version 1.00 Copyright (c) 1990 Borland International

ejemplo.c:

Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International

Available memory xxxxxx

C:\TRABAJO>

Después de esto, el directorio tendrá los archivos

ejemplo.c

turboc.cfg

ejemplo.obj

ejemplo.exe

El archivo EJEMPLO.OBJ es el objeto resultante de la compilación, y EJEMPLO.EXE es el ejecutable que se obtiene después del enlazado con los modulos de iniciación y bibliotecas de Turbo C.

Un inconveniente que podemos encontrar en este método es que las funciones suma() y producto() sólo sirven para el programa EJEMPLO.C. Si quisieramos usar estas funciones en otros programas, tendríamos que teclearlas de nuevo al editarlos. Esto no es demasiado problema en funciones como las del ejemplo, pero resulta muy incómodo para funciones con más código o que usemos habitualmente en nuestros programas. La solución consiste en guardar en archivos diferentes el programa EJEMPLO.C (la parte que contiene las declaraciones y la función main()) y las funciones suma() y producto(), por ejemplo, en archivos SUMA.C y PROD.C.

/* Programa EJEMPLO.C */

#include <stdio.h>

#inlcude <conio.h>

float suma (float, float);

float producto (float, float);

void main (void)

{

float a, b;

clrscr ();

printf ("Teclea dos números: ");

scanf ("%f %f", &a, &b);

printf ("\nSuma: %f", suma (a, b));

printf ("\nProducto: %f", producto (a, b));

}

/* Archivo SUMA.C: Función suma */

float suma (float x, float y);

{

return x + y;

}

/* Archivo PROD.C: Función producto */

float (producto (float x, float y)

{

return x * y;

}

Ahora compilaremos por separado cada uno de estos módulos y, posteriormente, haremos el enlazado.

C:\TRABAJO> tcc -c -ms ejemplo

Turbo C++ Version 1.00 Copyright (c) 1990 Borland International

ejemplo.c:

Available memory xxxxxx

C:\TRABAJO> tcc -c -ms prod

Turbo C++ Version 1.00 Copyright (c) 1990 Borland International

prod.c:

Available memory xxxxxx

C:\TRABAJO> tcc -c -ms suma

Turbo C++ Version 1.00 Copyright (c) 1990 Borland International

suma.c:

Available memory xxxxxx

C:\TRABAJO> tlink /x c0s ejemplo prod suma, ejemplo,, emu maths cs

Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International

C:\TRABAJO>

Después de esto, en el directorio C:\TRABAJO tendremos los siguientes archivos:

ejemplo.c

prod.c

suma.c

turboc.cfg

ejemplo.obj

prod.obj

suma.obj

ejemplo.exe

Los *.OBJ son los resultantes de las compilaciones de los *.C, y EJEMPLO.EXE es el ejecutable final.

Este método de trabajo permite tener por separado nuestras funciones compiladas (en formato .OBJ), disponibles para ser enlazadas con cualquier programa. Además, si modificamos uno de los módulos basta con recompilarlo y, posteriormente, hacer el enlazado, sin recompilar los módulos que no han sido modificados. Por ejemplo, si hacemos algún cambio en EJEMPLO.C, bastará con hacer:

C:\TRABAJO> tcc -c -ms ejemplo

Turbo C++ Version 1.00 Copyright (c) 1990 Borland International

ejemplo.c:

Available memory xxxxxx

C:\TRABAJO> tlink /x c0s ejemplo prod suma, ejemplo,, emu maths cs

Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International

C:\TRABAJO>

Pero para estos casos es muy útil el programa MAKE. Creamos el siguiente archivo de construcción MAKE, al que llamaremos EJEMPLO.MAK:

ejemplo.exe: ejemplo.obj prod.obj suma.obj

tlink /x c0s ejemplo prod suma, ejemplo,, emu maths cs

ejemplo.obj: ejemplo.c

tcc -c -ms ejemplo

prog.obj: prod.c

tcc -c -ms prod

suma.obj: suma.c

tcc -c -ms suma

Suponiendo que tenemos en el directorio C:\TRABAJO los siguientes archivos

ejemplo.c

prod.c

suma.c

turboc.cfg

ejemplo.mak

después de

C:\TRABAJO> make -fejemplo.mak

tendremos, además, los archivos

ejemplo.obj

prod.obj

suma.obj

ejemplo.exe

Si se modifica alguno de los módulos, digamos SUMA.C, y repetimos la orden

C:\TRABAJO> make -fejemplo.mak

observaremos que MAKE se encarga de recompilar SUMA.C y enlazar el SUMA.OBJ resultante con el resto de módulos objeto y bibliotecas, sin recompilar EJEMPLO.C ni PROD.C.

Otra posibilidad consiste en tener almacenados nuestros módulos objeto en una biblioteca. Supongamos que tenemos en C:\TRABAJO los archivos

ejemplo.c

prod.c

suma.c

turboc.cfg

ejemplo.obj

prod.obj

suma.obj

y hacemos

C:\TRABAJO> tlib milib +suma +prod

TLIB 3.0 Copyright (c) 1987, 1990 Borland International

C:\TRABAJO> del suma.obj (no es necesario)

C:\TRABAJO> del suma.obj (no es necesario)

Los archivos en C:\TRABAJO serán

ejemplo.c

prod.c

suma.c

turboc.cfg

ejemplo.obj

milib.lib

El enlazado se hace ahora

C:\TRABAJO> tlink /x c0s ejemplo, ejemplo,, emu maths cs milib

Turbo Link Version 3.0 Copyright (c) 1987, 1990 Borland International

C:\TRABAJO>

De este modo podemos tener una colección de módulos objeto disponible para cualquier programa mediante la biblioteca MILIB.LIB.

Para no tener que indicar en los archivos c0s, emu, maths y cs el camino de búsqueda c:\tc\lib (lo que puede dar problemas, al ser la línea de órdenes demasiado larga) es conveniente ejecutar previamente la orden APPEND c:\tc\lib (o bien incluirla en el archivo AUTOEXEC.BAT). Esta orden es similar a la orden PATH, en el sentido que indica a las aplicaciones dónde buscar los archivos que no se encuentren en el directorio actual.

196 Introducción al Lenguaje C

12. Compilación y enlazado 195