2011-02-16 75 views
18

链接到包含文件与链接到lib文件有什么区别?包括目录与lib目录概念问题

我对C/C++相当陌生,我很难弄清楚使用包含文件和静态lib文件来调用函数的区别。在我看来,include文件具有可以像.lib文件一样调用的函数。

+1

你知道编译和链接的区别吗?这可能有助于澄清答案。 – sstn 2011-02-16 21:37:29

回答

28

在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

// 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; 
} 

事实上,它会抱怨说它不知道什么是addsub。这是因为你试图在不声明它们存在的情况下使用它们 - 这正是声明的目的。所以你可能做到以下几点:

// 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文件的用途。它们包含相关函数的定义的预编译代码。你仍然需要include文件来让你知道lib中存在哪些函数。

编译链接阶段的目的是将这些预编译函数和刚才编译的函数合并成一个可执行文件。从本质上讲,你可以看一个静态lib作为一些预定义函数的预编译代码,它的匹配包含文件作为一个工具,让任何代码想要使用这些函数知道哪些是可用的以及它们是什么描述是。


*这不完全正确,但足以满足我们的目的。

+1

感谢您的详细解释。这是否意味着在创建库时,我们总是需要有一个.h文件来引用所有的函数?例如,如果我使用一堆.cpp文件和一个.h文件创建myLibrary.lib来声明我的函数,那么我必须将.h文件包含在我使用我的库引用库的任何程序中以及链接到myLibrary.lib? – foboi1122 2011-02-17 17:45:52

2

包含文件通常包含符号声明(函数,变量)。这让我们的编译器知道一个名字被定义(在头)或其他地方(在申报的情况下):

a.h: 

void a_useful_function(); //declaration 

,但你也可以有一个定义:

a.h: 

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

库是通常由标题暴露的函数的累积。标题通常是您要链接的库的接口。

但是,存在只有头文件的库,它们的声明和定义代码在相同的文件中。

你提到在你的问题包括目录。 include目录是编译器搜索解决#include“a.h”预处理器指令的地方。

但也有库目录,其中链接器搜索通常为头中的声明提供实现(定义)所需的库。

0

提供一种更简单的答案:

.lib文件是预编译库。如果包含.lib,则还需要包含.h/hpp头文件,以便您的编译器知道如何访问.lib中的函数。

当你编译你的程序时,从lib中使用的所有函数都只能被链接,它们会被重新编译。