В C ++ (и 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
#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;
}
Если вы попытаетесь скомпилировать main.cpp
как есть, он пожалуется, что не знает, что такое add
и sub
.Это потому, что вы пытаетесь использовать их, не заявляя, что они существуют - именно для этого и нужна декларация.Поэтому вы можете сделать следующее:
// 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;
}
Это будет работать, но не очень гибко.Если мы добавим новую функцию mul
, нам нужно пойти и добавить ее объявление в main.cpp
и во все остальные .cpp
файлы, которые ее используют (что очень много работы, если у вас много .cpp
файлов),Поэтому вместо этого мы помещаем все объявления в один файл (скажем, math.h
), поэтому нам нужно только поддерживать список объявлений в одном месте.Затем мы просто включаем math.h
в любой файл, который использует математические функции.Это цель заголовочных файлов (также называемых включаемыми файлами).
Это прекрасно работает, но может быть даже лучше.У нас есть файл main.cpp
и файл math.cpp
, которые компилируются каждый раз, когда вы компилируете программу *.Если ваши математические функции не меняются вообще, конечно, лучше скомпилировать их один раз и просто вставлять предварительно скомпилированные определения в ваш исполняемый файл всякий раз, когда вы перекомпилируете main.cpp
?Именно в этом и состоит цель .lib
файлов.Они содержат предварительно скомпилированный код для определений соответствующих функций.Вам все еще нужен файл включения, чтобы вы знали, какие функции существуют в lib.
Цель этапа компиляции компоновки - взять эти предварительно скомпилированные функции и функции, которые вы только что скомпилировали, и свернуть их.вместе в один исполняемый файл.
По сути, вы можете рассматривать статическую библиотеку как предварительно скомпилированный код для ряда предопределенных функций, а соответствующий ей включаемый файл - как инструмент, позволяющий любому коду желать использоватьте функции знают, какие доступны и каково их описание.
* Это не совсем верно, но здесь достаточно для наших целей.