22

考虑这段代码:

一.c:

#include <stdio.h>

int one() {
   printf("one!\n");
   return 1;
}

二.c:

#include <stdio.h>

int two() {
   printf("two!\n");
   return 2;
}

程序.c

#include <stdio.h>

int one();
int two();

int main(int argc, char *argv[]) 
{
   one();
   two();

   return 0;
}

我想将这些程序链接在一起。所以我这样做:

gcc -c -o one.o one.c
gcc -c -o two.o two.c
gcc -o a.out prog.c one.o two.o

这工作得很好。

或者我可以创建一个静态库:

ar rcs libone.a one.o
ar rcs libtwo.a two.o
gcc prog.c libone.a libtwo.a
gcc -L. prog.c -lone -ltwo

所以我的问题是:为什么我要使用第二个版本——我创建“.a”文件的那个版本——而不是链接我的“.o”文件?它们似乎都是静态链接的,那么彼此之间是否存在优势或架构差异?

4

6 回答 6

46

通常,库是可以在多个程序中使用的目标文件的集合。

在您的示例中没有优势,但您可能已经这样做了:

ar rcs liboneandtwo.a one.o two.o

然后链接您的程序变得更简单:

gcc -L. prog.c -loneandtwo

这真的是一个包装问题。您是否有一组目标文件自然形成一组可在多个程序中重用的相关功能?如果是这样,那么它们可以明智地归档到静态库中,否则可能没有任何优势。

最后的链接步骤有一个重要的区别。您链接的任何目标文件都将包含在最终程序中。仅当库中的目标文件有助于解析其他目标文件中的任何未定义符号时,才会包含这些目标文件。如果不这样做,它们将不会链接到最终的可执行文件中。

于 2009-12-05T18:12:56.783 回答
12

不同之处在于可执行文件的大小,尽管可能不适用于您的示例。

链接到库时,仅包含可执行文件使用的位。链接目标文件时,您将获取整个内容。

例如,如果您的可执行文件必须包含数学库中的每个数学函数,而您只使用一个,那么它会比它需要的大得多,并且包含大量未使用的代码。

将其与 Windows 的动态链接模型进行对比是很有趣的。在那里,操作系统必须完全加载可执行文件使用的所有 Dll(动态链接库),这可能导致 RAM 膨胀。这种模型的优点是您的可执行文件本身较小,并且链接的 Dll 可能已经在某些其他可执行文件使用的内存中,因此不需要再次加载它们。

在静态链接中,库函数为每个可执行文件单独加载。

于 2009-12-05T18:17:23.583 回答
3

从技术上讲,结果是完全一样的。通常,您为实用函数创建库,因此您只需链接库,而不是向链接器提供数十个目标文件。

顺便说一句,创建一个仅包含一个 .o 文件的 .a 文件绝对没有意义。

于 2009-12-05T18:10:46.013 回答
2

您可以将文件集合放在存档 (.a) 文件中以供以后重复使用。标准库就是一个很好的例子。

有时将大型项目组织到库中是有意义的。

于 2009-12-05T18:12:04.247 回答
1

主要优点是当您必须链接时,您可以只指定一个库而不是所有单独的目标文件。管理文件还有一个小优势,可以处理一个库而不是一堆目标文件。一度,这也显着节省了磁盘空间,但目前的硬盘价格使这一点变得不那么重要了。

于 2009-12-05T18:11:31.573 回答
0

每当我被问到这个问题(我的团队中的新人),“为什么(或者有时甚至是'什么是')a .a?”,我使用以下使用 .zip 作为类比的答案。

“dotAy 就像您在构建 exe/lib 时要链接的所有 dotOhs 的 zip 文件。节省磁盘空间,而且无需键入所有涉及的 dotOhs 的名称。”

到目前为止,这似乎让他们明白了。;)

于 2009-12-15T14:33:46.470 回答