链接到库时,include和link之间有什么区别?

什么包括和链接真的吗? 有什么区别? 为什么我需要指定它们? 当我写#include math.h然后编写-lm来编译它时, #include math.h-lm分别做了什么?

据我所知,在链接库时,您需要其.h文件及其.o文件。 这是否建议#include math.h意味着接受.h文件而-lm接收.o文件?

因为头文件只包含声明,而.o文件(或类似的东西,如.obj,.dll或.lib)包含方法的定义。 你打开.h文件,你不会看到方法的代码,因为它在库中。 一个原因是商业性的,因为您需要公开您的代码并在您的公司中拥有源代码。 库已编译,因此您可以公开它。 头文件只说编译器,它可以在库中找到哪些类和方法。

头文件是一种内容列表加上一种编译器的字典。 它告诉编译器库提供了什么,并给出特殊值可读的名称。

库文件本身包含内容。

你需要一个头(接口描述)和库(实现)的原因是C将两者分开,而不是像C#或Java那样的语言。 可以编译一个C函数(例如通过调用gcc -c ),即使被调用的库不存在,它也会调用库代码。 包含接口描述的标题就足够了。 (这对于C#或Java来说是不可能的;必须存在程序集和类文件/ jar文件。)在链接阶段虽然库必须在那里,即使它是动态的,afaik。

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

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

所以从理论上讲,如果你在一个已知的位置有一个正确注释的库,你可能会编写一个编译器来编译一个C函数,而不需要函数声明和类型定义; 编译器必须生成适当的声明。 编译器必须知道要解析哪个库(这与在VS中设置C#项目“Reference”或在Java中具有类路径和名称/类对应关系相对应)。

最简单的方法是使用众所周知的调试格式,如stabs或dwarf,并使用一个小的帮助程序从中提取接口定义,该程序使用API​​作为调试格式,提取信息并生成一个C头,它是前面的每个源文件。 这将是编译器驱动程序的工作,实际的编译器仍然会忽略它。

你问的问题完全是两件事。 别担心,我会向你解释。 使用#符号指示预处理器包含math.h头文件,这些文件内部包含fabs(),ceil()等函数原型。然后使用-lm指示链接器,包含预编译函数fabs(),ceil()等的定义在exe文件中起作用。 现在,您可能会问为什么我们必须显式链接数学函数的库文件,这与其他函数不同,答案是,这是由于一些未定义的历史原因。