为什么从.o创build一个.a文件来进行静态链接?

考虑这个代码:

one.c:

#include <stdio.h> int one() { printf("one!\n"); return 1; } 

two.c:

 #include <stdio.h> int two() { printf("two!\n"); return 2; } 

prog.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 

这工作得很好。

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

 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 

所以我的问题是:为什么我会使用第二个版本 – 我创build了一个“.a”文件 – 而不是链接我的“.o”文件? 它们似乎都是静态连接的,所以在一个与另一个之间是否有优势或者架构差异?

Solutions Collecting From Web of "为什么从.o创build一个.a文件来进行静态链接?"

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

在你的例子中没有优势,但你可能已经做了:

 ar rcs liboneandtwo.a one.o two.o 

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

 gcc -L. prog.c -loneandtwo 

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

在最后的链接步骤中有一个重要的区别。 您链接的任何对象文件都将包含在最终的程序中。 库中的对象文件只有在帮助解决其他对象文件中的任何未定义符号时才会包含在内。 如果他们不这样做,他们将不会被链接到最终的可执行文件。

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

链接到库时,只有可执行文件使用的位被合并。 链接一个目标文件时,你把所有的东西都拿走了。

例如,如果您的可执行文件只有在使用数学库时才需要包含数学函数库中的每一个数学函数,那么它将比需要的大得多,并包含大量未使用的代码。

将这与Windows的动态链接模型进行对比是有趣的。 在那里,操作系统必须完全加载你的可执行程序使用的所有Dll(动态链接库),这可能导致内存膨胀。 这种模式的优点是你的可执行文件本身就比较小,链接的Dlll可能已经被其他可执行文件使用的内存,所以不需要再次加载。

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

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

顺便说一句,创建一个只包含一个.o文件的.a文件是毫无意义的。

您可以将一组文件放在一个存档(.a)文件中以备后用。 标准库就是一个很好的例子。

有时将大型项目组织成图书馆是有道理的。

主要优点是当你必须链接时,你可以指定一个库而不是所有的单独的对象文件。 在管理文件方面还有一个小小的优势,就是处理一个库而不是一堆目标文件。 同时,这也节省了大量的磁盘空间,但目前的硬盘价格并不那么重要。

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

“dotAy就像所有dotOhs的zip文件一样,在建立你的exe / lib的时候你想链接的是这个文件,节省磁盘空间,加上一个不需要输入所有dotOhs的名字。

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