【问题标题】:include directories vs. lib directory concept question包含目录与 lib 目录概念问题
【发布时间】:2011-02-16 21:32:11
【问题描述】:

链接到包含文件和链接到 lib 文件有什么区别?

我是 C/C++ 的新手,我很难弄清楚使用包含文件和静态 lib 文件调用函数之间的区别。在我看来,包含文件具有可以像 .lib 文件一样调用的函数。

【问题讨论】:

  • 你知道编译和链接的区别吗?这可能有助于澄清答案。

标签: c++


【解决方案1】:

在 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 中存在哪些函数。

编译链接阶段的目的是把这些预编译的函数和你刚刚编译的函数,一起滚动到一个单独的可执行文件中。

本质上,您可以将静态库视为许多预定义函数的预编译代码,并将其匹配的包含文件视为一种工具,让任何想要使用这些函数的代码知道哪些可用以及它们的描述是。


* 这并不完全正确,但对于我们这里的目的来说已经足够了。

【讨论】:

  • 感谢您的详尽解释。这是否意味着在创建库时,我们总是需要一个 .h 文件来引用所有函数?因此,例如,如果我使用一堆 .cpp 文件和一个 .h 文件创建一个 myLibrary.lib 来声明我的函数,那么我必须将 .h 文件包含在我使用我的库的任何程序中以将库引用为以及链接到 myLibrary.lib?
  • @foboi1122:你基本上明白了,是的。只是为了澄清一下,这样做(即使用包含文件)不是要求(您可以只需在使用它们的文件中声明您的函数,如根据我上一个代码示例),但标准做法是使用包含来简化代码管理。
  • 感谢您为我解决这个问题。感谢大家的帮助
【解决方案2】:

提供一个更简单的答案:

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

当你编译你的程序时,所有从库中使用的函数都只是链接,它们不会再次编译。

【讨论】:

    【解决方案3】:

    包含文件通常包含符号(函数、变量)的声明。这让编译器知道名称已定义(在标头中)或其他地方(在声明的情况下):

    a.h:
    
    void a_useful_function(); //declaration 
    

    但你也可以有一个定义:

    a.h:
    
    void a_useful_function()
    {
        //... do something
    }
    

    库是通常由标头公开的函数的集合。标头通常是您要链接的库的接口。

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

    您在问题中提到包含目录。包含目录是编译器搜索以解析 #include "a.h" 预处理器指令的位置。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-23
      • 1970-01-01
      • 2016-04-07
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多