Académique Documents
Professionnel Documents
Culture Documents
Junio 2014
El objetivo de este articulo es el de presentar los fundamentos de la compilacin en C, C++ y de
la programacin modular.
Esto nos permitir comprender mejor los mensajes de error del compilador. Las nociones
abordadas aqu son independientes del sistema operativo utilizado (Windows o Linux). No
obstante, supondremos que estamos bajo Linux para ver con ms detalle lo que ocurre durante
la compilacin de un programa en C o C++.
Introduccin
Instalacin de un compilador C y C++
Bajo Linux
Bajo Windows
Las fases de compilacin
1) El preprocesado
2) La compilacin
3) El enlazado
Warning y errores
Las grandes etapas para escribir un programa en C o C++
Escribir el cdigo fuente
Compilar
Ejecucin
Los errores clsicos
Error de compilacin
Error de enlazado
Programacin modular: multi-definicin, bucles de inclusin
Funcion declaradapero no encontrada
Ir ms lejos con la compilacin: makefile
Introduccin
De manera general, el objetivo de un compilador es el de convertir un archivo texto (conteniendo
cdigo fuente) en un archivo binario (por ejemplo un ejecutable). Una vez creado el ejecutable,
ste es ejecutado como cualquier programa. Este programa puede ejecutarse sin que se
disponga del cdigo fuente. Un lenguaje compilado (como C o C++) es diferente a un lenguaje
interpretado (por ejemplo un script de shell) o a un seudo-interpretado (por ejemplo python). En
C, la compilacin transformar el cdigo C de un programa en cdigo nativo, es decir una serie
de instrucciones binarias que pueden ser directamente comprendidas por el procesador.
Bajo Windows
Podemos utilizar dev-cpp o code::blocks: dos entornos de desarrollo libres que se basan en gcc
y g++: http://www.bloodshed.net/devcpp.html http://www.codeblocks.org/ Articulo relacionado:
http://es.kioskea.net/faq/sujet 2817 compilar un programa en c bajo linux
1) El preprocesado
El compilador comienza por aplicar cada instruccin pasada al preprocesador (todas las lneas
que comienzan con #, entre estas las #define). Estas instrucciones son en realidad muy simples
ya que nicamente copian o eliminan secciones de cdigo sin compilarlas. Es en esta fase que
las #define que se encuentran en un archivo fuente (.c o .cpp) o en un header (.h o .hpp) son
reemplazadas por cdigo C/C+. Al final de esta etapa, no habrn instrucciones comenzando por
#.
2) La compilacin
Luego, el compilador compila cada archivo fuente (.c y .cpp), es decir crea un archivo binario (.o)
para cada archivo fuente, excepto para el archivo conteniendo la funcin main. Esta fase
constituye la compilacin propiamente dicha. Estas dos primeras etapas son realizadas por cc
cuando se utiliza gcc/g++.
3) El enlazado
Finalmente, el compilador une cada archivo .o con los archivos binarios de las libreras que son
utilizadas (archivos .a y .so bajo Linux, archivos .dll bajo Windows). Especialmente, verifica que
cada funcin llamada en el programa no est solamente declarada (esto es hecho durante la
compilacin) sino tambin implementada. Tambin verifica que una funcin no est
implementada en varios archivos .o. Esta fase constituye la fase final para obtener un ejecutable
(.exe bajo Windows, generalmente sin extensin bajo Linux). Esta fase es realizada por ld
cuando se utiliza gcc/g++.
Warning y errores
Evidentemente, en un entorno de desarrollo, basta con hacer clic sobre build y estas tres fases
se llevan a cabo automticamente. No obstante, es importante conocerlas para interpretar
correctamente los mensajes de error o warning de un compilador. Un warning significa que el
cdigo es ambiguo y que puede ser interpretado de manera diferente de un compilador a otro,
pero el ejecutable puede ser creado. En cambio, un error significa que el cdigo no ha podido
ser compilado completamente y que el ejecutable no ha podido ser creado.
Compilar
Bajo Linux llamamos directamente a gcc (-W y Wall permiten mostrar ms mensajes para
verificar si el cdigo es limpio, -o plop.exe indica que el ejecutable que ser creado debe
llamarse plop.exe):
gcc -W -Wall -o plop.exe plop.c
Implcitamente el compilador hace las tres etapas descritas anteriormente. 1) El preprocesado
/* Todo lo que es definido por <stdio.h>, incluyendo printf() */
int main(){
printf("plop !\n");
return 0;
}
Ejecucin
Tan solo queda ejecutarlo:
./plop.exe
Lo que da como esperado:
plop!
Si algn error se produce aqu (error de segmentacin, falta de memoria, etc.), por lo general
habr que recurrir a un depurador (por ejemplo gdb o ddd), revisar el cdigo fuente, etc. En todos
los casos, no ser un problema de compilacin. Articulo relacionado: error de segmentacin
Atencin: Bajo Windows existen dos mtodos para ejecutar un programa: Mtodo 1: podemos
ejecutar un programa a travs de los comando ms-dos (haciendo clic en Inicio / Ejecutar y
escribir cmd). Con el comando cd nos colocamos en el directorio y ejecutamos el programa. En
este caso todo ira bien. Mtodo 2: Si ejecutamos el programa desde el explorador, no podremos
ver el programa a menos que pongamos una pausa justo antes del final del programa.
#include <stdio.h>
int main(){
printf("plop !\n");
getchar(); /* el programa se detiene a menos que presionemos una tecla */
return 0;
}
Supongamos que olvidamos incluir en nuestro cdigo fuente el archivo <stdio.h> (en el que est
declarada la funcin printf), o un ";", tendremos entonces un mensaje de error de compilacin. Es
el error ms tpico.
Error de enlazado
Estos errores son ms sutiles, ya que no tienen que ver con la sintaxis, sino con la manera en
que esta estructurado y compilado el programa. Son fciles de reconocer cuando se utiliza gcc o
g++ ya que los mensajes de error correspondientes mencionan a ld (el linker). Primer ejemplo:
multidefinicin Un error de enlazado puede ocurrir cuando se escribe el cdigo de un programa
utilizando varios ficheros. A continuacin veremos este tipo de error: Supongamos que nuestro
programa es escrito utilizando 3 archivos: a.h, a.c, y main.c. El encabezado a.h esta incluido en
los dos archivos fuente main.c y a.c. el archivo main.c contiene la funcin main(). 1) Si
compilamos nicamente a.c, el archivo que no contiene la funcin main, es necesario indicarle
al compilador (opcin c en gcc) sino no sabr cmo crear un ejecutable, ya que no hay punto
de partida. Es por ello que el archivo conteniendo la funcin main (sin opcin c) y los otros
archivos fuente se compilan de manera diferente. En este caso:
gcc -W -Wall -c a.c
gcc -W -Wall -o plop.exe main.c a.o
Las opciones W y Wall permiten mostrar ms mensajes de warning. -El primer comando
construye a.o a partir de a.c. -El segundo genera el binario asociado a main.c, lo une con a.o, y
produce as un ejecutable (plop.exe) Podemos observar que si el programa contiene un error en
a.c, el compilador producir un error al momento de compilar a.c. esto provocar errores en
cascada en los otros archivos. Por ello cuando un programa no compila, se comienza por lo
primeros mensajes de error, los solucionamos, lo volvemos a compilar, etchasta que todos los
errores sean solucionados. 2) Recordemos que normalmente, declaramos la funcin en el
encabezado (por ejemplo a.h):
void plop();
y que lo implementamos en el archivo fuente (por ejemplo a.c):
#include "a.h"
#include <stdio.h>
void plop(){
printf("plop !\n");
}
Ahora supongamos que implementamos la funcin plop() en a.h (es decir que la funcin no est
declarada en a.h). En otras palabras, el archivo a.h contiene
#include <stdio.h>
void plop(){
printf("plop !\n");
}
leyendo el encabezado a.h, incluyendo b.h. en ese momento B_H no est definido, por lo tanto
de la misma manera entramos en el encabezado b.h y activamos A_H. Ahora leemos el
contenido de b.h que quiere incluir a.h. Entramos nuevamente en a.h pero esta vez, A_H est
definido por lo que ignoramos el contenido del encabezado. Terminamos de leer el encabezado
b.h, lo que resuelve el #include "b.h" que estbamos tratando en a.h. Luego terminamos el
encabezado b.h. Este caso puede parecer extrao, pero hay que tener en cuenta que cuando un
encabezado est incluido varias veces, pueden aparecer multidefiniciones (en particular si son
declaradas estructuras en el encabezado). Por ello es que ponemos sistemticamente este
mecanismo de cerrojo en todos los encabezado.