Вопрос о директориях с каталогом vs lib

В чем разница между связыванием и включением файлов или ссылкой на файлы lib?

Я новичок в C/С++, и мне сложно определить разницу между использованием файлов include и статическим файлом lib для вызова функций. На мой взгляд, файлы include имеют функции, которые можно вызвать так же, как .lib файлы.

Ответ 1

В С++ (и C и других подобных языках) функция называется объявлением и определением.

Объявление - это просто краткое утверждение, которое объявляет, что функция существует и как выглядит интерфейс. Рассмотрим базовую функцию add, которая объединяет два целых числа. Это объявление может выглядеть следующим образом:

int add(int, int);

Это означает, что существует функция add, которая принимает два целых числа и возвращает целое число ". Он не указывает, что фактически делает функция, несмотря на то, что мы можем сделать хорошее предположение, основанное на его имени.

Определение функции - это то, где мы точно определяем, что делает функция. Это может быть то, что вы считаете фактическим кодом функции. Используя функцию add в качестве примера:

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

Итак, как это соответствует вашему вопросу? Ну, предположим, что у нас есть ряд математических функций в math.cpp:

// math.cpp

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

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

А также предположим, что мы решили использовать некоторые из них в нашей основной функции в main.cpp:

// main.cpp

int main (int argc, char* argv[])
{
    printf("1 + 2 = %d\n", add(1, 2));
    printf("8 - 3 = %d\n", sub(8, 3));
}

Если вы попытаетесь скомпилировать main.cpp как есть, он будет жаловаться, что он не знает, что такое add и sub. Это происходит из-за того, что вы пытаетесь использовать их, не объявляя, что они существуют, что и является декларацией. Таким образом, вы можете сделать следующее:

// main.cpp

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

int main (int argc, char* argv[])
{
    printf("1 + 2 = %d\n", add(1, 2));
    printf("8 - 3 = %d\n", sub(8, 3));
}

Это будет работать, но не очень гибко. Если мы добавим новую функцию mul, нам нужно пойти и добавить ее объявление в main.cpp и каждый другой файл .cpp, который его использует (это большая работа, если у вас много файлов .cpp), Итак, что мы делаем, вместо этого мы помещаем все объявления в один файл (например, math.h), поэтому нам нужно поддерживать список объявлений только в одном месте. Затем мы просто включаем math.h в любой файл, который использует математические функции. Это назначение файлов заголовков (файлы include.k.a.).

Это отлично работает, но может быть даже лучше. Как бы то ни было, у нас есть файл main.cpp и файл math.cpp, оба из которых скомпилированы каждый раз при компиляции программы *. Если ваши математические функции не меняются вообще, лучше ли их компилировать один раз и просто вставлять предварительно скомпилированные определения в ваш исполняемый файл всякий раз, когда вы перекомпилируете main.cpp? Это как раз цель файлов .lib. Они содержат предварительно скомпилированный код для определения соответствующих функций. Вам все еще нужен файл include, чтобы вы знали, какие функции существуют в lib.

Цель этапа компоновки компиляции состоит в том, чтобы взять эти предварительно скомпилированные функции и функции, которые вы только что скомпилировали, и свернуть их вместе в один исполняемый файл.

По существу, вы можете посмотреть статическую библиотеку как предварительно скомпилированный код для ряда предопределенных функций, а ее сопоставление включает в себя файл как инструмент, позволяющий любому коду, желающему использовать эти функции, знать, какие из них доступны и что их описание есть.

Ничего себе, это закончилось совсем немного дольше, чем я предполагал.:) Надеюсь, это поможет прояснить ситуацию!

* Это не совсем верно, но для наших целей это достаточно.

Ответ 2

Включаемые файлы обычно содержат объявление символа (функция, переменная). Это позволяет компилятору знать, что имя определено (в заголовке) или в другом месте (в случае объявления):

a.h:

void a_useful_function(); //declaration 

но вы также можете определить:

a.h:

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

Библиотеки - это накопление функций, которые обычно отображаются заголовками. Заголовок обычно является интерфейсом к библиотеке, с которой вы будете ссылаться.

Существуют только библиотеки с заголовком, которые имеют свои коды деклараций и определений в одном файле.

Вы упомянули каталоги в своем вопросе. Каталоги include - это места, где компилятор ищет, чтобы разрешить директиву препроцессора #include "a.h".

Но есть также библиотечные каталоги, в которых компоновщик ищет необходимые библиотеки, которые обычно предоставляют реализации (определения) объявлениям в ваших заголовках.

Ответ 3

чтобы обеспечить более простой ответ:

.lib файлы представляют собой предварительно скомпилированные библиотеки. если вы включили .lib, вам также нужно включить файлы заголовков .h/hpp, поэтому ваш компилятор знает, как получить доступ к функциям в .lib.

когда вы скомпилируете свою программу, все функции, используемые из lib, связаны только, они снова скомпилированы.