¿Cuál es la diferencia entre – 1) Preprocesador, enlazador, 2) Archivo de encabezado, biblioteca? ¿Es correcto mi entendimiento?

12 minutos de lectura

¿Cual es la diferencia entre 1 Preprocesador enlazador 2
Paagalpan

Bien, hasta esta mañana estaba completamente confundido entre estos términos. Supongo que tengo la diferencia, con suerte.

En primer lugar, la confusión fue que, dado que el preprocesador ya incluye los archivos de encabezado en el código que contiene las funciones, ¿qué funciones de biblioteca vincula el enlazador al archivo de objeto producido por el ensamblador/compilador? Parte de la confusión surgió principalmente debido a mi ignorancia sobre la diferencia entre un archivo de encabezado y una biblioteca.

Después de buscar un poco en Google y desbordar la pila (¿es ese el término? :p), deduje que el archivo de encabezado contiene principalmente las declaraciones de funciones, mientras que la implementación real está en otro archivo binario llamado biblioteca (todavía no estoy 100% seguro de esto).

Entonces, supongamos en el siguiente programa: –

#include<stdio.h>
int main()
{
      printf("whatever");
      return 0;
}

El preprocesador incluye el contenido del archivo de encabezado en el código. El compilador/compilador+ensamblador hace su trabajo, y finalmente el enlazador combina este archivo de objeto con otro archivo de objeto que en realidad ha almacenado la forma printf() obras.

¿Estoy en lo correcto en mi entendimiento? Puede que me haya equivocado… ¿podría ayudarme, por favor?

Editar: Siempre me he preguntado acerca de C++ STL. Siempre me confundió en cuanto a qué es exactamente, ¿una colección de todos esos encabezados o qué? Ahora, después de leer las respuestas, ¿puedo decir que STL es un archivo de objeto/algo que se parece a un archivo de objeto?

Y también, pensé dónde podría leer las definiciones de funciones de funciones como pow(), sqrt() etc. etc. Abriría los archivos de cabecera y no encontraría nada. Entonces, ¿la definición de la función en la biblioteca está en forma binaria ilegible?

  • El entendimiento que mencionas bajo el código es correcto.

    – Alok Guardar

    29 de agosto de 2012 a las 12:24

  • y finalmente se produce un ejecutable u otra librería…. 😉

    – cerebro peligroso

    29 de agosto de 2012 a las 12:30

  • Se puede encontrar una explicación (particular para C, pero C++ es más o menos lo mismo) en mi tutorial de C, en el capítulo sobre encabezados: masters-of-the-void.com/book10.htm

    – ulitestigo

    20 de enero de 2014 a las 16:29

¿Cual es la diferencia entre 1 Preprocesador enlazador 2
Richard Cámaras

El archivo fuente AC pasa por dos etapas principales, (1) la etapa del preprocesador donde el código fuente C es procesado por la utilidad del preprocesador que busca las directivas del preprocesador y realiza esas acciones y (2) la etapa de compilación donde el código fuente C procesado es luego realmente compilado para producir archivos de código de objeto.

El preprocesador es una utilidad que manipula texto. Toma como entrada un archivo que contiene texto (generalmente código fuente C) que puede contener directivas de preprocesador y genera una versión modificada del archivo aplicando las directivas encontradas a la entrada de texto para generar una salida de texto.

El archivo no tiene que ser código fuente C porque el preprocesador está manipulando el texto. He visto el C Preprocssor usado para extender el make utilidad al permitir que las directivas de preprossor se incluyan en un archivo make. El archivo make con las directivas del preprocesador de C se ejecuta a través de la utilidad del preprocesador de C y la salida resultante se introduce en make para hacer la compilación real del objetivo de fabricación.

Bibliotecas y enlaces

Una biblioteca es un archivo que contiene código objeto de varias funciones. Es una forma de empaquetar la salida de varios archivos fuente cuando se compilan en un solo archivo. Muchas veces se proporciona un archivo de biblioteca junto con un archivo de encabezado (archivo de inclusión), normalmente con una extensión de archivo .h. El archivo de encabezado contiene las declaraciones de funciones, las declaraciones de variables globales, así como las directivas de preprocesador necesarias para la biblioteca. Entonces, para usar la biblioteca, incluye el archivo de encabezado provisto usando el #include directiva y se vincula con el archivo de la biblioteca.

Una buena característica de un archivo de biblioteca es que proporciona la versión compilada de su código fuente y no el código fuente en sí. Por otro lado, dado que el archivo de biblioteca contiene código fuente compilado, el compilador utilizado para generar el archivo de biblioteca debe ser compatible con el compilador que se utiliza para compilar sus propios archivos de código fuente.

Hay dos tipos de bibliotecas de uso común. El primer tipo y más antiguo es la biblioteca estática. La segunda y más reciente es la biblioteca dinámica (Dynamic Link Library o DLL en Windows y Shared Library o SO en Linux). La diferencia entre los dos es cuando las funciones en la biblioteca están vinculadas al ejecutable que usa el archivo de la biblioteca.

El enlazador es una utilidad que toma varios archivos de objetos y archivos de biblioteca para crear el archivo ejecutable. Cuando se usa una función o variable externa o global en el archivo fuente C, se usa una especie de marcador para decirle al enlazador que la dirección de la función o variable debe insertarse en ese punto.

El compilador de C solo sabe qué hay en el código fuente que compila y no sabe qué hay en otros archivos, como archivos de objetos o bibliotecas. Entonces, el trabajo del enlazador es tomar los diversos archivos de objetos y bibliotecas y hacer las conexiones finales entre las partes reemplazando los marcadores con conexiones reales. Entonces, un enlazador es una utilidad que “vincula” los diversos componentes, reemplazando el marcador de una función o variable global en los archivos y bibliotecas de objetos con un enlace al código de objeto real que se generó para esa función o variable global.

Durante la etapa del enlazador es cuando se hace evidente la diferencia entre una biblioteca estática y una biblioteca dinámica o compartida. Cuando se utiliza una biblioteca estática, el código de objeto real de la biblioteca se incluye en el ejecutable de la aplicación. Cuando se usa una biblioteca dinámica o compartida, el código de objeto incluido en el ejecutable de la aplicación es un código para encontrar la biblioteca compartida y conectarse con ella cuando se ejecuta la aplicación.

En algunos casos, el mismo nombre de función global se puede usar en varios archivos de objetos o bibliotecas diferentes, por lo que el enlazador normalmente solo usará el primero que encuentre y emitirá una advertencia sobre otros que se encuentren.

Resumen de compilación y enlace

Entonces, el proceso básico para compilar y vincular un programa en C es:

  • La utilidad del preprocesador genera la fuente C que se va a compilar.

  • el compilador compila la fuente C en código objeto generando un conjunto de archivos objeto

  • el enlazador vincula los diversos archivos de objetos junto con cualquier biblioteca en un archivo ejecutable

Lo anterior es el proceso básico, sin embargo, cuando se usan bibliotecas dinámicas, puede volverse más complicado, especialmente si parte de la aplicación que se genera tiene bibliotecas dinámicas que está generando.

el cargador

También está la etapa en la que la aplicación se carga realmente en la memoria y comienza la ejecución. Un sistema operativo proporciona una utilidad, el cargador, que lee el archivo ejecutable de la aplicación, lo carga en la memoria y luego inicia la ejecución de la aplicación. El punto de inicio o punto de entrada para el ejecutable se especifica en el archivo ejecutable, por lo que después de que el cargador lea el archivo ejecutable en la memoria, iniciará la ejecución del ejecutable saltando a la dirección de memoria del punto de entrada.

Un problema con el que se puede encontrar el enlazador es que a veces puede encontrarse con un marcador cuando está procesando los archivos de código de objeto que requieren una dirección de memoria real. Sin embargo, el enlazador no conoce la dirección de memoria real porque la dirección variará dependiendo de en qué parte de la memoria se cargue la aplicación. Entonces, el enlazador marca eso como algo que la utilidad del cargador debe corregir cuando el cargador está cargando el ejecutable en la memoria y preparándose para comenzar a ejecutarse.

Con las CPU modernas con dirección virtual admitida por hardware para la asignación o traducción de direcciones físicas, este problema de la dirección de memoria real rara vez es un problema. Cada aplicación se carga en la misma dirección virtual y la traducción de la dirección del hardware se ocupa de la dirección física real. Sin embargo, las CPU más antiguas o las CPU de menor costo, como los microcontroladores que carecen del soporte de hardware de la unidad de administración de memoria (MMU) para la traducción de direcciones, aún necesitan que se solucione este problema.

Puntos de entrada y el tiempo de ejecución de C

Un último tema es el C Runtime y el main() y el punto de entrada del ejecutable.

El tiempo de ejecución de C es un código objeto proporcionado por el fabricante del compilador que contiene el punto de entrada para una aplicación que está escrita en C. El main() La función es el punto de entrada proporcionado por el programador que escribe la aplicación; sin embargo, este no es el punto de entrada que ve el cargador. los main() C Runtime llama a la función después de que se inicia la aplicación y el código de C Runtime configura el entorno para la aplicación.

C Runtime no es la biblioteca estándar de C. El propósito de C Runtime es administrar el entorno de tiempo de ejecución de la aplicación. El propósito de la Biblioteca C estándar es proporcionar un conjunto de funciones de utilidad útiles para que un programador no tenga que crear las suyas propias.

Cuando el cargador carga la aplicación y salta al punto de entrada proporcionado por C Runtime, C Runtime realiza las diversas acciones de inicialización necesarias para proporcionar el entorno de tiempo de ejecución adecuado para la aplicación. Una vez hecho esto, el tiempo de ejecución de C llama al main() para que el código creado por el desarrollador o programador de la aplicación comience a ejecutarse. Cuando el main() regresa o cuando el exit() se llama a la función, C Runtime realiza las acciones necesarias para limpiar y cerrar la aplicación.

  • Gracias por una explicación tan detallada. Como se mencionó – One problem the linker can run into is that sometimes it may come across a marker when it is processing the object code files that requires an actual memory address. ¿Podría dar un ejemplo de una situación en la que se requiera una dirección de memoria real?

    –Yug Singh

    18 de noviembre de 2019 a las 6:37


  • @YugSingh, algo que me viene a la mente es cuando se carga una DLL. Estaba pensando en su pregunta y me pregunto si partes de esta respuesta necesitan actualizarse con memoria virtual y tecnologías MMU comunes incluso hasta procesadores integrados.

    – Richard Cámaras

    18 de noviembre de 2019 a las 18:29

Esta es una fuente extremadamente común de confusión. Creo que la forma más fácil de entender lo que está sucediendo es tomar un ejemplo simple. Olvídese de las bibliotecas por un momento y considere lo siguiente:

$ cat main.c
extern int foo( void );
int main( void ) { return foo(); }
$ cat foo.c
int foo( void ) { return 0; }
$ cc -c main.c
$ cc -c foo.c
$ cc main.o foo.o

La declaracion extern int foo( void ) está realizando exactamente la misma función que el archivo de encabezado de una biblioteca. foo.o está realizando la función de la biblioteca. Si entiendes este ejemplo, y por qué ni cc main.c ni cc main.o trabajo, entonces entiende la diferencia entre los archivos de encabezado y las bibliotecas.

  • Gracias… No estoy seguro de entender completamente este ejemplo… pero eso es porque no entiendo la palabra ‘extren’. Lo investigaré un poco más tarde y te molestaré nuevamente en caso de dudas. 🙂

    – Paagalpan

    30 de agosto de 2012 a las 7:23

  • Parece que el comando cat de Linux se está utilizando para crear dos archivos de código fuente C pequeños y simples, main.c y foo.c, cada uno de los cuales primero se compila y luego se vincula. El comando cc tiene suficiente inteligencia para que, si especifica archivos de objeto, los archivos main.o y foo.o, simplemente realice un enlace usando esos archivos.

    – Richard Cámaras

    30 de agosto de 2012 a las 12:31

  • cat no está creando los archivos, simplemente mostrándolos.

    – William Pursell

    30 de agosto de 2012 a las 16:59

Sí, casi correcto. Excepto que el enlazador no vincula archivos de objetos, sino también bibliotecas; en este caso, es la biblioteca estándar de C (libc) la que está vinculada a su archivo de objetos. El resto de sus suposiciones parecen ser ciertas sobre las etapas de compilación + diferencia entre un encabezado y una biblioteca.

  • @DevSolar excepto que no lo es. Eso es creado a partir de archivos de objetos, pero ciertamente no es un archivo de objetos en sí mismo.

    usuario529758

    29 de agosto de 2012 a las 12:26

  • @H2CO3: las bibliotecas compartidas a menudo se consideran archivos de objetos por derecho propio.

    – Fred Foo

    29 de agosto de 2012 a las 12:35

  • @H2CO3: no, bibliotecas compartidas. Las bibliotecas estáticas son ar archivos de archivos de objetos antiguos simples. Las bibliotecas compartidas son archivos de “objetos compartidos” (.so extensión en Linux y algunos otros sistemas).

    – Fred Foo

    29 de agosto de 2012 a las 12:42

  • @larsmans Soy consciente de eso. Pero técnicamente, a pesar de tener el nombre de “objeto compartido”, no son archivos de objetos. están correctamente vinculado utilizando el enlazador, al igual que un ejecutable y se puede abrir para la ejecución directa de sus contenidos (por ejemplo, el dlopen() API) porque contienen información de ubicación/dirección que los archivos de objeto no tienen.

    usuario529758

    29 de agosto de 2012 a las 12:44

  • @H2CO3: dlopen() comienza con “dl” porque es una llamada al dinámica enlace cargador. Árbitro. “.dll” en Windows (dinámico Enlace Biblioteca)…

    – DevSolar

    29 de agosto de 2012 a las 12:52


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad