C中的静态库与动态库

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

C库或多或少是建立在同一前提下的: 人们可以通过重用某人(包括您过去的自己)所做的工作来节省大量时间和精力 。 我们还从以下事实中受益:达尔文可能比我们更好地表达了他的理论,并且类似地,从事诸如C标准库之类工作的开发人员的集体意识很可能为打印字符串编写了比我们给定的时间更强大的功能。约束(至少在我的情况下如此)。

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

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

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

  ar -r -c libalphabet.a print_alphabet.o 

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

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

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

  ranlib libalphabet .a 

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

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

要创建动态库,我们首先需要使用标志-fPIC编译所有包含链接阶段所需功能的文件,该标志生成位置独立代码。

  gcc -c -fPIC * .c 

接下来,我们需要将该目标代码转换为共享库。 与使用静态库生成一样,我们没有使用存档器工具,而是在gcc另一次运行中使用了-shared标志。 确保包括-o标志以为您的库提供自定义名称。 对于共享库,库需要扩展名.so ,按照约定,前缀lib表示它是一个库。 为了包括所有目标代码,我们使用通配符*后跟.o (目标文件)扩展名。

  gcc libalphabet.so *.o -o libalphabet.so *.o 

最后,如果要检查并查看新创建的库中包含哪些确切函数,则可以将命令nm-D标志一起使用,该标志引用已初始化数据部分中的符号。

  nm -D libalphabet.so 

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

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

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

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

考虑函数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()函数的静态库的任何程序中:简而言之,静态链接。

 静态库: 
╔════════════════════════════╦════════════════════ ══════════╗
s优点s缺点║
╠════════════════════════════╬════════════════════ ══════════╣
║1.没有运行时依赖项║1.使用大量内存
║if 2.如果需要重新编译
║更新║
╚════════════════════════════牛皮════════════════════ ══════════╝
vs.动态库:╔════════════════════════════╦═══════════════ ═════════════╗
s优点s缺点║
╠════════════════════════════╬════════════════════ ════════╣
║1.占用较少的内存║1.必须存在库║
program为了程序program
run跑run
║2.无需重新编译║2.便携式性较低║
║主程序following
update更新║
╚════════════════════════════牛皮════════════════════ ════════╝

谢谢阅读。