incluir directorios vs. pregunta sobre el concepto de directorio lib

6 minutos de lectura

¿Cuál es la diferencia entre vincular para incluir archivos y vincular para archivos lib?

Soy bastante nuevo en C/C++ y me está costando entender la diferencia entre usar archivos de inclusión y un archivo lib estático para llamar a funciones. En mi opinión, los archivos de inclusión tienen funciones que uno puede llamar como archivos .lib.

  • ¿Conoces la diferencia entre compilar y enlazar? Esto podría ayudar a aclarar la respuesta.

    – sstn

    16 de febrero de 2011 a las 21:37

avatar de usuario
Mac

En C++ (y C y otros lenguajes similares) se dice que una función tiene tanto un declaración y un definición.

La declaración es simplemente una declaración breve que declara que la función existe y cómo se ve su interfaz. Considere una función básica add que suma dos enteros. Su declaración podría ser similar a la siguiente:

int add(int, int);

Esto significa que “existe una función add que toma dos enteros y devuelve un entero”. No especifica qué hace realmente la función, a pesar de que podemos hacer una buena suposición en función de su nombre.

La definición de la función es donde definimos exactamente lo que la función lo hace. Esto podría ser lo que considera que es el código de función real. Utilizando el add funcionar como un ejemplo:

int add (int a, int b)
{
    return a + b;
}

Entonces, ¿cómo encaja esto con tu pregunta? Bueno, supongamos que tenemos varias funciones matemáticas en math.cpp:

// math.cpp

int add (int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

Y también supongamos que decidimos usar algunos de estos en nuestra función principal en main.cpp:

// main.cpp

#include <iostream>

int main (int argc, char* argv[])
{
    std::cout << "1 + 2 = " << add(1, 2) << std::endl;
    std::cout << "8 - 3 = " << sub(8, 3) << std::endl;
}

Si intenta compilar main.cpp tal como es, se quejará de que no sabe qué add y sub son. Esto se debe a que está tratando de usarlos sin declarar que existen, que es exactamente para lo que sirve una declaración. Así que podrías hacer lo siguiente:

// main.cpp

#include <iostream>

int add(int, int);
int sub(int, int);

int main (int argc, char* argv[])
{
    std::cout << "1 + 2 = " << add(1, 2) << std::endl;
    std::cout << "8 - 3 = " << sub(8, 3) << std::endl;
}

Esto funcionaría, pero no es muy flexible. Si añadimos una nueva función multenemos que ir y agregar su declaración a main.cpp y todos los demás .cpp archivo que lo usa (que es mucho trabajo si tiene muchos .cpp archivos). Entonces, lo que hacemos es poner todas las declaraciones en un solo archivo (digamos, math.h) por lo que solo tenemos que mantener la lista de declaraciones en un solo lugar. Entonces, simplemente incluimos math.h en cualquier archivo que utilice las funciones matemáticas. Este es el propósito de los archivos de encabezado (también conocidos como archivos de inclusión).

Esto funciona muy bien, pero podría ser aún mejor. Tal como está, tenemos un main.cpp archivo, y un math.cpp archivo, los cuales se compilan cada vez que compila el programa*. Si sus funciones matemáticas no cambian en absoluto, seguramente es mejor compilarlas una vez y simplemente insertar las definiciones precompiladas en su ejecutable cada vez que vuelva a compilar main.cpp? Ese es exactamente el propósito de .lib archivos Contienen el código precompilado para definiciones de las funciones correspondientes. Todavía necesita el archivo de inclusión para saber qué funciones existen en la biblioteca.

El propósito de la etapa de vinculación de la compilación es tomar estas funciones precompiladas y las funciones que acaba de compilar, y juntarlas en un solo archivo ejecutable.

Esencialmente, puede ver una biblioteca estática como el código precompilado para una serie de funciones predefinidas, y su archivo de inclusión coincidente como una herramienta para que cualquier código que quiera usar esas funciones sepa cuáles están disponibles y cuál es su descripción.


* Esto no es estrictamente cierto, pero es suficiente para nuestros propósitos aquí.

  • Gracias por la completa explicación. ¿Significa esto que al crear bibliotecas, siempre necesitaremos tener un archivo .h que haga referencia a todas las funciones? Entonces, por ejemplo, si creo myLibrary.lib usando un montón de archivos .cpp y un archivo .h para declarar mis funciones, tendría que incluir el archivo .h en cualquier programa en el que use mi biblioteca para hacer referencia a la biblioteca como así como vincular a myLibrary.lib?

    – foboi1122

    17 de febrero de 2011 a las 17:45

  • @foboi1122: Básicamente tienes la idea, sí. Sin embargo, solo para aclarar, hacerlo de esa manera (es decir, con un archivo de inclusión) no es un requisito (tú pueden simplemente declare sus funciones en el archivo en el que las usa, según mi último ejemplo de código), pero la práctica estándar es usar un include para simplificar la administración del código.

    – Mac

    17 de febrero de 2011 a las 19:58


  • Gracias por aclarármelo. agradezco la ayuda de todos

    – foboi1122

    17 de febrero de 2011 a las 21:47

avatar de usuario
cppanda

Para dar una respuesta más simple:

Los archivos .lib son bibliotecas precompiladas. Si incluye un .lib, también debe incluir los archivos de encabezado .h/hpp, para que su compilador sepa cómo acceder a las funciones en el .lib.

Cuando compila su programa, todas las funciones utilizadas desde la biblioteca solo se vinculan, no se compilan nuevamente.

avatar de usuario
David

Los archivos de inclusión normalmente contienen la declaración de un símbolo (una función, una variable). Esto le permite al compilador saber que un nombre está definido (en el encabezado) o en otro lugar (en el caso de una declaración):

a.h:

void a_useful_function(); //declaration 

pero también puedes tener una definición:

a.h:

void a_useful_function()
{
    //... do something
}

Las bibliotecas son una acumulación de funciones que normalmente se exponen mediante encabezados. El encabezado suele ser la interfaz de una biblioteca con la que se vinculará.

Sin embargo, existen bibliotecas de solo encabezado que tienen sus declaraciones y códigos de definiciones en el mismo archivo.

Usted menciona incluir directorios en su pregunta. Los directorios de inclusión son los lugares donde el compilador busca para resolver un #include "a.h" directiva de preprocesador.

Pero también hay directorios de bibliotecas donde el enlazador busca las bibliotecas necesarias que generalmente brindan implementaciones (definiciones) a las declaraciones en sus encabezados.

¿Ha sido útil esta solución?