.o文件和.lib文件有什么区别?
概念上,编译单元(源文件/目标文件中的代码单元)要么完全链接,要么完全不链接。虽然有一些实现(编译器和链接器之间相互配合程度较高),能够在链接时从目标文件中删除未使用的代码,但这并不改变在程序中包含2个具有冲突符号名称的编译单元是一个错误的问题。
举个实际的例子,假设您的库有两个函数foo
和bar
,并且它们在一个目标文件中。如果我想使用bar
,但我的程序已经有了一个名为foo
的外部符号,那么我就会遇到错误。即使实现可能能够为我解决此问题,代码仍然是不正确的。
另一方面,如果我有一个包含两个独立目标文件的库文件,一个包含foo
,另一个包含bar
,则只有包含bar
的文件将被引入我的程序中。
编写库时,应避免在同一目标文件中包含多个函数,除非它们必须一起使用。这样做会使链接您的库的应用程序变得臃肿,并增加符号冲突的可能性。个人而言,我更喜欢在存在疑虑时采取分开文件的方式——甚至有用的是,如果后者比较复杂,可以将foo_create
和foo_free
放在不同的文件中,这样不需要调用foo_free
的简短单次程序就可以避免拉入深度释放的代码(甚至可能避免拉入free
本身的实现)。
它们实际上是非常不同的,特别是在旧链接器中。
.o(或.obj)文件是目标文件,它们包含编译器生成的代码的输出。 它仍处于中间格式,例如,大多数引用仍未解析。 通常,源文件与目标文件之间存在一对一的映射关系。
.a(或.lib)文件是存档文件,也称为库文件,它们是一组目标文件。
所有操作系统都有工具,允许您将目标文件添加/删除/列出到库文件中。
另一个区别,特别是在旧链接器中,是在链接它们时如何处理文件。 一些链接器将完整的目标文件放入最终二进制文件中,而不管实际使用了什么,而将有用的信息从库文件中提取出来。
现在大多数链接器足够聪明,可以删除未使用的所有内容。