关于C静态库


今天,我们将用C编程语言介绍静态库。 我知道您几乎无法平息您的兴奋,所以让我们直接进入。

在C语言中,库基本上只是在执行程序时可以使用的目标文件的有组织的(或换句话说:索引的)集合。 哦,如果您想知道:目标文件只是编译器在编译过程中的实际输出。 目标文件主要是机器代码,但是具有额外的信息,这些信息使它们可以在编译的链接阶段与其他文件合并,以形成一个可执行文件。 在这里可以找到有关编译过程的更多信息。

想象一下,您正在撰写有关马达加斯加陆龟的进化和历史的论文。 您只想直接撰写有关乌龟的文章,而不想为重新审视达尔文的整个进化论而烦恼。 自然地,您只是简单地用名字来称呼他的理论:“达尔文的进化论”。此外,您还引用了达尔文的开创性著作《物种起源》 ,所以那些不知道“进化论”是什么的人,可以去图书馆 并准确地看到这三个词的结合,就代表了。

C库或多或少是建立在同一前提下的:通过重用某人(包括您过去的自我)已经完成的工作,可以节省大量的时间和精力。 我们还从以下事实中受益:达尔文可能比我们更好地编写了关于进化的文章,并且类似地,从事C标准库之类的开发人员的集体意识可能为打印字符串编写了比我们更好的函数(至少就我而言是正确的)。

库很像可执行文件,但是不是直接执行,而是使用指定的参数从程序中通过名称调用它们。

静态库与动态(有时称为:共享)库的不同之处在于,静态库代码直接链接到最终的可执行文件中。

动态链接指向内存中函数的地址,而不是直接将目标代码粘贴到其中。实际的目标代码仅在程序运行时(运行时)才出现。

与动态链接相比,静态链接有两个缺点。

  • 大小:程序中的每个函数都将直接链接目标代码。这等效于每次您要说“进化论”时都复制和粘贴“论物种起源 ”。 正如您所能想象的那样,有关乌龟的论文将比其需要的论文体积更大,效率更低。
  • 更新:如果您静态链接的库已更新(针对错误修复或其他原因),则必须重新编译整个程序。

考虑函数print_alphabet() 。 它位于一个名为print_alphabet.c的文件中,看起来像这样:

  #include  void print_alphabet(void) 
{
printf(“ abcdefghijklmnopqrstuvwxyz”);
}
  • #include 包括C标准I / O库,其中包含printf()函数。
  • printf()是一个标准的库函数,仅打印一个字符串。

我们的print_alphabet()函数不会做任何浮华的事情; 它做一件事,并且做得很好:打印字母。

我们可以使用以下命令将该程序转换为目标代码:

  gcc -c print_alphabet.c 

我们的文件现在是print_alphabet.o ,其中包含目标代码而不是源代码。 此目标代码直接粘贴到使用包含print_alphabet()函数的静态库的任何程序中:简而言之,静态链接。

要创建静态库,我们使用命令ar代表程序“ archiver”。 该程序可以从我们的命令行创建,列出和修改静态库或“归档文件”。

要为上面的示例中使用的函数创建静态库,请使用以下命令:

  ar -r -c libalphabet.a print_alphabet.o 

此命令将创建一个名为libalphabet.a的静态库,并将文件print_alphabet.o的副本放入其中。

  • -r标志告诉归档程序将所有较旧的目标文件替换为较新的目标文件。
  • -u标志告诉存档程序创建文件libalphabet.a如果不存在)。

但是,还不止这些。 我们可以并且应该为我们的库建立索引,以便编译器可以更快,更有效地找到我们的链接程序。 创建库索引(或更新现有索引)的命令是ranlib ,它以库为参数:

 兰利布  图书馆   。一种 

此步骤并非总是必需的,因为有时它是自动完成的。

要查看我们库的内容,我们可以使用ar -t组合。 但是,如果我们需要更多信息,则可以使用nm命令。 此命令列出每个符号的值,类型和名称。

说,出于某种奇怪的原因,您想要一个将字母打印两次的程序。 您巧妙地将其double_alphabet.c ,其中的代码如下所示:

  #include“ alphabet.h” int main(void) 
{
print_alphabet();
print_alphabet();返回(0);
}
  • #include "alphabet.h"链接一个头文件,该头文件包含我们的print_alphabet()函数的名称,返回类型和参数类型(如果不包括此内容,则编译器会抱怨)。
  • int main(void)是我们在执行程序时运行的主要函数。
  • 这两个print_alphabet()函数将打印两次字母表。

但是,您可能想知道:我们的程序如何知道print_alphabet()作用? 我的朋友说,那就是图书馆的来源。

在编译时,我们使用命令gcc然后是要编译的程序,在这种情况下: gcc double_alphabet.c将生成一个可执行文件,该可执行文件在运行时将打印两次字母。 还是会? 这不会起作用,因为编译器不知道什么是print_alphabet() ,这就是为什么我们需要添加包含print_alphabet()函数代码的库作为gcc的参数。 要将libalphabet.a库与程序链接,我们可以简单地使用以下命令:

 海湾合作委员会   double_alphabet.c libalphabet.a 

请记住,由于我们未使用-o标志来指定名称,因此文件的输出将称为a.out 。 因此,当我们使用./a.out运行程序时,将看到以下内容:

感谢您的阅读。 🐢