What does include and link REALLY do? What are the differences? And why do I need to specify both of them? When I write #include math.h
and then write -lm
to compile it, what does #include math.h
and -lm
do respectively?
什么包括和链接真的吗?有什么区别?为什么我需要指定它们?当我写#include math.h然后编写-lm来编译它时,#include math.h和-lm分别做了什么?
In my understanding, when linking a library, you need its .h file and its .o file. Does this suggest #include math.h
means take in the .h file while -lm
take in the .o file?
据我所知,在链接库时,您需要其.h文件及其.o文件。这是否建议#include math.h意味着接受.h文件而-lm接收.o文件?
4 个解决方案
#1
1
Its because headers files contain only declaration,and .o file (or something like that, like .obj, .dll or .lib) contains definitions of methods. Of you open .h file, you will not see code of methods, because that is in libraries. One reason is commercial, because you need to public your code and have the source codes in your company. Libraries are compiled, so you could public it. Header files only says compiler, what classes and methods it can find in library.
因为头文件只包含声明,而.o文件(或类似的东西,如.obj,.dll或.lib)包含方法的定义。你打开.h文件,你不会看到方法的代码,因为它在库中。一个原因是商业性的,因为您需要公开您的代码并在您的公司中拥有源代码。库已编译,因此您可以公开它。头文件只说编译器,它可以在库中找到哪些类和方法。
#2
1
The header files are kind of a table-of-contents plus a kind of dictionary for the compiler. It tells the compiler what the library offers and gives special values readable names.
头文件是一种内容列表加上一种编译器的字典。它告诉编译器库提供了什么,并给出特殊值可读的名称。
The library file itself contains the contents.
库文件本身包含内容。
#3
1
The reason that you need both a header (the interface description) and the library (the implementation) is that C separates the two clearer than languages like C# or Java do. One can compile a C function (e.g. by invoking gcc -c <sourcefile>
) which calls library code even when the called library is not present; the header, which contains the interface description, suffices. (This is not possible with C# or Java; the assemblies resp. class files/jars must be present.) During the link stage though the library must be there, even when it's dynamic, afaik.
你需要一个头(接口描述)和库(实现)的原因是C将两者分开,而不是像C#或Java那样的语言。可以编译一个C函数(例如通过调用gcc -c
With C#, Java, or script languages, by contrast, the implementation contains all information necessary to define the interface. The compiler (which is not as clearly separated from the linker) looks in the jar file or the C# assembly which contain called implementations and obtains information about function signatures and types from there.
相比之下,使用C#,Java或脚本语言,实现包含定义接口所需的所有信息。编译器(与链接器没有明确分离)查找jar文件或包含被调用实现的C#程序集,并从那里获取有关函数签名和类型的信息。
Theoretically, that information could probably be present in a library written in C as well — it's basically the debug information. But the classic C compiler (as opposed to the linker) is oblivious to libraries or object files and cannot parse them. (One should remember that the "compiler" executable you usually use to compile a C program , e.g. gcc, is a "compiler driver" which interpretes the command line arguments and calls the programs which actually do stuff, e.g. the preprocessor, actual compiler and actual linker, to create the desired output.)
从理论上讲,这些信息可能也存在于用C语言编写的库中 - 它基本上就是调试信息。但是经典的C编译器(与链接器相对)无视库或目标文件,无法解析它们。 (应该记住,您通常用于编译C程序的“编译器”可执行文件,例如gcc,是一个“编译器驱动程序”,它解释命令行参数并调用实际执行操作的程序,例如预处理程序,实际编译器和实际链接器,以创建所需的输出。)
So in theory, if you have a properly annotated library in a known location, you could probably write a compiler which compiles a C function against it without having function declarations and type defintions; the compiler would have to produce the proper declarations. The compiler would have to know which library to parse (which corresponds to setting a C# project "Reference" in VS or having a class path and name/class correspondence in Java).
所以从理论上讲,如果你在一个已知的位置有一个正确注释的库,你可能会编写一个编译器来编译一个C函数,而不需要函数声明和类型定义;编译器必须生成适当的声明。编译器必须知道要解析哪个库(这与在VS中设置C#项目“Reference”或在Java中具有类路径和名称/类对应关系相对应)。
It would probably be easiest to use a well-known debugging format like stabs or dwarf and extract the interface definitions from it with a little helper program which uses the API for the debug format, extracts the information and produces a C header which is prepended to every source file. That would be the job of the compiler driver, and the actual compiler would still be oblivious to that.
最简单的方法是使用众所周知的调试格式,如stabs或dwarf,并使用一个小的帮助程序从中提取接口定义,该程序使用API作为调试格式,提取信息并生成一个C头,它是前面的每个源文件。这将是编译器驱动程序的工作,实际的编译器仍然会忽略它。
#4
0
What you are asking are entirely two different things. Don't worry , i will explain them to you. You use # symbol to instruct the preprocessor to include the math.h header files which internally contain the function prototypes of fabs(),ceil() etc.. And you use -lm to instruct the linker, to include the pre-compiled function definitions of fabs(),ceil() etc. functions in the exe file . Now, you may ask why we have to explicitly link library file of math functions unlike for other functions and the answer is ,it is due to some undefined historical reasons.
你问的问题完全是两件事。别担心,我会向你解释。使用#符号指示预处理器包含math.h头文件,这些文件内部包含fabs(),ceil()等函数原型。然后使用-lm指示链接器,包含预编译函数fabs(),ceil()等的定义在exe文件中起作用。现在,您可能会问为什么我们必须显式链接数学函数的库文件,这与其他函数不同,答案是,这是由于一些未定义的历史原因。
#1
1
Its because headers files contain only declaration,and .o file (or something like that, like .obj, .dll or .lib) contains definitions of methods. Of you open .h file, you will not see code of methods, because that is in libraries. One reason is commercial, because you need to public your code and have the source codes in your company. Libraries are compiled, so you could public it. Header files only says compiler, what classes and methods it can find in library.
因为头文件只包含声明,而.o文件(或类似的东西,如.obj,.dll或.lib)包含方法的定义。你打开.h文件,你不会看到方法的代码,因为它在库中。一个原因是商业性的,因为您需要公开您的代码并在您的公司中拥有源代码。库已编译,因此您可以公开它。头文件只说编译器,它可以在库中找到哪些类和方法。
#2
1
The header files are kind of a table-of-contents plus a kind of dictionary for the compiler. It tells the compiler what the library offers and gives special values readable names.
头文件是一种内容列表加上一种编译器的字典。它告诉编译器库提供了什么,并给出特殊值可读的名称。
The library file itself contains the contents.
库文件本身包含内容。
#3
1
The reason that you need both a header (the interface description) and the library (the implementation) is that C separates the two clearer than languages like C# or Java do. One can compile a C function (e.g. by invoking gcc -c <sourcefile>
) which calls library code even when the called library is not present; the header, which contains the interface description, suffices. (This is not possible with C# or Java; the assemblies resp. class files/jars must be present.) During the link stage though the library must be there, even when it's dynamic, afaik.
你需要一个头(接口描述)和库(实现)的原因是C将两者分开,而不是像C#或Java那样的语言。可以编译一个C函数(例如通过调用gcc -c
With C#, Java, or script languages, by contrast, the implementation contains all information necessary to define the interface. The compiler (which is not as clearly separated from the linker) looks in the jar file or the C# assembly which contain called implementations and obtains information about function signatures and types from there.
相比之下,使用C#,Java或脚本语言,实现包含定义接口所需的所有信息。编译器(与链接器没有明确分离)查找jar文件或包含被调用实现的C#程序集,并从那里获取有关函数签名和类型的信息。
Theoretically, that information could probably be present in a library written in C as well — it's basically the debug information. But the classic C compiler (as opposed to the linker) is oblivious to libraries or object files and cannot parse them. (One should remember that the "compiler" executable you usually use to compile a C program , e.g. gcc, is a "compiler driver" which interpretes the command line arguments and calls the programs which actually do stuff, e.g. the preprocessor, actual compiler and actual linker, to create the desired output.)
从理论上讲,这些信息可能也存在于用C语言编写的库中 - 它基本上就是调试信息。但是经典的C编译器(与链接器相对)无视库或目标文件,无法解析它们。 (应该记住,您通常用于编译C程序的“编译器”可执行文件,例如gcc,是一个“编译器驱动程序”,它解释命令行参数并调用实际执行操作的程序,例如预处理程序,实际编译器和实际链接器,以创建所需的输出。)
So in theory, if you have a properly annotated library in a known location, you could probably write a compiler which compiles a C function against it without having function declarations and type defintions; the compiler would have to produce the proper declarations. The compiler would have to know which library to parse (which corresponds to setting a C# project "Reference" in VS or having a class path and name/class correspondence in Java).
所以从理论上讲,如果你在一个已知的位置有一个正确注释的库,你可能会编写一个编译器来编译一个C函数,而不需要函数声明和类型定义;编译器必须生成适当的声明。编译器必须知道要解析哪个库(这与在VS中设置C#项目“Reference”或在Java中具有类路径和名称/类对应关系相对应)。
It would probably be easiest to use a well-known debugging format like stabs or dwarf and extract the interface definitions from it with a little helper program which uses the API for the debug format, extracts the information and produces a C header which is prepended to every source file. That would be the job of the compiler driver, and the actual compiler would still be oblivious to that.
最简单的方法是使用众所周知的调试格式,如stabs或dwarf,并使用一个小的帮助程序从中提取接口定义,该程序使用API作为调试格式,提取信息并生成一个C头,它是前面的每个源文件。这将是编译器驱动程序的工作,实际的编译器仍然会忽略它。
#4
0
What you are asking are entirely two different things. Don't worry , i will explain them to you. You use # symbol to instruct the preprocessor to include the math.h header files which internally contain the function prototypes of fabs(),ceil() etc.. And you use -lm to instruct the linker, to include the pre-compiled function definitions of fabs(),ceil() etc. functions in the exe file . Now, you may ask why we have to explicitly link library file of math functions unlike for other functions and the answer is ,it is due to some undefined historical reasons.
你问的问题完全是两件事。别担心,我会向你解释。使用#符号指示预处理器包含math.h头文件,这些文件内部包含fabs(),ceil()等函数原型。然后使用-lm指示链接器,包含预编译函数fabs(),ceil()等的定义在exe文件中起作用。现在,您可能会问为什么我们必须显式链接数学函数的库文件,这与其他函数不同,答案是,这是由于一些未定义的历史原因。