链接到包含文件与链接到lib文件有什么区别?
我是C / C ++的新手,我很难搞清楚使用包含文件和静态lib文件来调用函数之间的区别。在我看来,包含文件具有可以像.lib文件一样调用的函数。
答案 0 :(得分:37)
在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
包含到任何使用数学函数的文件中。这是头文件(a.k.a.include files)的目的。
这很好用,但可能会更好。实际上,我们有一个main.cpp
文件和一个math.cpp
文件,每次编译程序时都会编译它们。如果您的数学函数根本没有改变,那么最好将它们编译一次,然后只要重新编译main.cpp
就将预编译的定义插入到可执行文件中?这正是.lib
文件的目的。它们包含相关函数的定义的预编译代码。您仍然需要包含文件来让您知道lib中存在哪些函数。
编译链接阶段的目的是获取这些预编译的函数和刚刚编译的函数,并将它们一起滚动到一个可执行文件中。
基本上,您可以将静态库视为许多预定义函数的预编译代码,并将其匹配包含文件作为工具,让任何想要使用这些函数的代码知道哪些是可用的以及它们的描述是什么是。
<小时/> *这不完全正确,但足以满足我们的目的。
答案 1 :(得分:2)
包含文件通常包含符号声明(函数,变量)。这让编译器知道名称是在(在标题中)或其他地方(在声明的情况下)定义的:
a.h:
void a_useful_function(); //declaration
但你也可以有一个定义:
a.h:
void a_useful_function()
{
//... do something
}
库是函数的累积,通常由标题公开。标题通常是您要链接的库的接口。
只存在标题库,但它们的声明和定义代码在同一个文件中。
您在提问中提及包含目录。 include目录是编译器搜索以解析#include“a.h”预处理程序指令的地方。
但是还有一些库目录,其中链接器搜索所需的库,这些库通常为头文件中的声明提供实现(定义)。
答案 2 :(得分:1)
提供更简单的答案:
.lib文件是预编译库。如果包含.lib,则还需要包含.h / hpp头文件,以便编译器知道如何访问.lib中的函数。
编译程序时,lib中使用的所有函数都只是链接的,它们会被重新编译。