Herramientas de usuario

Herramientas del sitio


compilacion

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
compilacion [2012/09/06 12:53] – [Link] lmateucompilacion [2014/09/04 13:42] (actual) – [Preproceso] lmateu
Línea 1: Línea 1:
-===== Fases de la Compilación =====+===== Etapas de la Compilación =====
  
 La compilación de un programa en C pasa por varias etapas desde La compilación de un programa en C pasa por varias etapas desde
Línea 49: Línea 49:
 Recuerde que cada identificador que se usa en C debe haber sido declarado previamente, de otro Recuerde que cada identificador que se usa en C debe haber sido declarado previamente, de otro
 modo se considera un error.  El peligro que se corre es declarar una variable o función modo se considera un error.  El peligro que se corre es declarar una variable o función
-de un tipo en un archivo, pero de otro en otro archivo.  El compilador no reclama en+de un tipo en un archivo, pero de otro tipo en otro archivo.  El compilador no reclama en
 este caso porque simplemente no tiene la información para detectar el error.  Por eso este caso porque simplemente no tiene la información para detectar el error.  Por eso
 se denomina compilación **separada**. se denomina compilación **separada**.
Línea 77: Línea 77:
   % gcc -E prog.c   % gcc -E prog.c
      
-La salida estandar mostrará:+La salida estándar mostrará:
  
   int main(int argc, char **argv) {   int main(int argc, char **argv) {
Línea 156: Línea 156:
      
   int f() {   int f() {
 +    b= 1.0;
     return g(a);     return g(a);
   }   }
Línea 169: Línea 170:
   int main() {   int main() {
     int x= f();     int x= f();
-    printf("%d\n", x);+    printf("%d %d %f\n", x, a, b);
     return x;     return x;
   }   }
      
   int g(int x) {   int g(int x) {
 +    a= 2;
     return x;     return x;
   }   }
Línea 180: Línea 182:
 al ensablador que no reserve espacio para ella porque se trata de una promesa de que otro archivo al ensablador que no reserve espacio para ella porque se trata de una promesa de que otro archivo
 la va a declarar.  Por otra parte b no es una referencia pendiente porque no lleva el atributo la va a declarar.  Por otra parte b no es una referencia pendiente porque no lleva el atributo
-'extern' Gcc invoca el linker de esta forma:+'extern'.
  
-  ln a.o b.o+La fase de link en Unix la realiza el comando ''ld'', que viene de //loader// Sin embargo este es 
 +un error histórico, porque su tarea no es la de un //loader// (cargardor).  Normalmente el cargador 
 +es la componente del núcleo del sistema operativo que carga un archivo ejecutable en la memoria del 
 +computador para que sea ejecutado.  De todas formas, el nombre 
 +se conserva quizás por compatibilidad.  Gcc invoca el linker de esta forma: 
 + 
 +  ld a.o b.o ... otros argumentos ...
  
  
Línea 228: Línea 236:
  
 Las bibliotecas son archivos con la extensión '.a' que empaquetan un sin número de archivos '.o' con el objeto Las bibliotecas son archivos con la extensión '.a' que empaquetan un sin número de archivos '.o' con el objeto
-de manejarlos como una unidad.  Estas bibliotecas se crean con el comando ar:+de manejarlos como una unidad.  Por ejemplo supongamos que tenemos los siguientes archivos:
  
-  ar r bib.a f1.o f2.o f3.o+  /* bib1.c */ 
 +  void g(); 
 +   
 +  void f() { 
 +    g(); 
 +  }
  
-Luego se pueden especificar en gcc:+  /* bib2.c */ 
 +  void g() { 
 +  }
  
-  gcc a.c b.c bib.a+  /* bib3.c */ 
 +  void h() { 
 +  }
  
-Si los archivos a.c o b.c contiene una referencia pendiente que se ubica en algún archivo '.o' +Compilamos ambos archivos con:
-contenido en bib.a, entonces se agrega ese archivo al binario.+
  
-Uno de los bugs más difíciles de diagnosticar que me ha tocado presenciar ocurrión cuando+  % gcc -c bib1.c bib2.c bib3.c 
 + 
 +Lo que genera los archivos bib1.o y bib2.o.  Creamos la bibliloteca bib.a con: 
 + 
 +  % ar r bib.a bib1.o bib2.o bib3.o 
 + 
 +Ahora podemos usar f o g desde otro programa: 
 + 
 +  /* a.c */ 
 +  int main() { 
 +    f(); 
 +  } 
 + 
 +Compilamos incluyendo la biblioteca con: 
 + 
 +  % gcc a.c bib.a 
 + 
 +Como a.o incluye una referencia pendiente a f, el linker la busca en las bibliotecas y la encuentra 
 +en bib1.o, por lo tanto agrega bib1.o completo al binario.  Pero ese a su vez tiene una 
 +referencia pendiente a g y la encuentra en bib2.o al binario.  Como h no se referencia en ningún 
 +lado, el archivo bib3.o no se agrega al binario ejecutable. 
 + 
 +Uno de los bugs más difíciles de diagnosticar que me ha tocado presenciar ocurrió cuando
 un función de biblioteca llamaba a otra función dentro de la misma biblioteca pero que casualmente un función de biblioteca llamaba a otra función dentro de la misma biblioteca pero que casualmente
 se llamaba igual que una variable global de los fuentes.  El linker no cargó la función de la biblioteca se llamaba igual que una variable global de los fuentes.  El linker no cargó la función de la biblioteca
Línea 245: Línea 283:
 ¡El programa se caía con un segmentation fault inexplicable! ¡El programa se caía con un segmentation fault inexplicable!
  
 +Esto se puede reproducir cambiando a.c por:
 +
 +  /* a.c */
 +  float g= 3.14;
 +  int main() {
 +    f();
 +  }
  
 +Ejercicio: Compile y ejecute para observar el segmentation fault.  Cuando se invoca g, se redirige
 +la ejecución hacia la variable en punto flotante g, como si ahí hubiesen instrucciones.
compilacion.1346936009.txt.gz · Última modificación: 2012/09/06 12:53 por lmateu