c - 链接到库时,include 和 link 有什么区别?

标签 c linker

include 和 link 的真正作用是什么?有什么区别?为什么我需要同时指定它们? 当我编写 #include math.h 然后编写 -lm 来编译它时,#include math.h - lm分别做什么?

据我了解,在链接库时,您需要它的 .h 文件和它的 .o 文件。这是否表明 #include math.h 意味着接收 .h 文件,而 -lm 接收 .o 文件?

最佳答案

您需要 header (接口(interface)描述)和库(实现)的原因是 C 比 C# 或 Java 等语言更清楚地将两者分开。可以编译一个 C 函数(例如通过调用 gcc -c <sourcefile> ),即使被调用的库不存在,它也会调用库代码;包含接口(interface)描述的 header 就足够了。 (这对于 C# 或 Java 是不可能的;程序集 resp。类文件/jar 必须存在。)在链接阶段,虽然库必须存在,即使它是动态的,afaik。

相比之下,对于 C#、Java 或脚本语言,实现包含定义接口(interface)所需的所有信息。编译器(与链接器没有明确分开)查看包含调用实现的 jar 文件或 C# 程序集,并从那里获取有关函数签名和类型的信息。

理论上,该信息也可能存在于用 C 编写的库中 — 它基本上是调试信息。但是经典的 C 编译器(与链接器相反)不会注意到库或目标文件,也无法解析它们。 (应该记住,您通常用于编译 C 程序的“编译器”可执行文件,例如 gcc,是一个“编译器驱动程序”,它解释命令行参数并调用实际执行操作的程序,例如预处理器,实际编译器和实际链接器,以创建所需的输出。)

因此理论上,如果您在已知位置有一个正确注释的库,您可能会编写一个编译器,在没有函数声明和类型定义的情况下针对它编译 C 函数;编译器必须生成正确的声明。编译器必须知道要解析哪个库(这对应于在 VS 中设置 C# 项目“引用”或在 Java 中具有类路径和名称/类对应关系)。

可能最简单的方法是使用像 stabs 或 dwarf 这样的众所周知的调试格式,并使用一个小的帮助程序从中提取接口(interface)定义,该程序使用调试格式的 API,提取信息并生成一个 C 头文件,它被添加到每个源文件中。那将是编译器驱动程序的工作,而实际的编译器仍然不会注意到这一点。

关于c - 链接到库时,include 和 link 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26562335/

相关文章:

c - 在用户空间启用写入组合 IO 访问

c - 我想按字母顺序对结构进行排序,但是如果我进行排序,我的程序不会给出任何输出

c - fread - 读取并跳过内存内容

linux - 在 debian 上链接 allegro 5

linux - 无法识别共享库文件格式

c++ - 我如何在链接描述文件中使用存档中的目标文件?

c - 在 C 中遇到段错误

c - 为什么这个添加被默默地忽略了?

c++ - OpenCV 未解析的外部符号 - 需要其他库吗?

c++ - 是否可以将 gcc 编译库与 MSVC 一起使用?