有什么区别 - 1)预处理器,链接器,2)头文件,库?我的理解是否正确?

时间:2022-11-26 02:04:39

Okay, until this morning I was thoroughly confused between these terms. I guess I have got the difference, hopefully.

好的,直到今天早上我才对这些术语感到困惑。我想我有所不同,希望如此。

Firstly, the confusion was that since the preprocessor already includes the header files into the code which contains the functions, what library functions does linker link to the object file produced by the assembler/compiler? Part of the confusion primarily arose due to my ignorance about the difference between a header file and a library.

首先,令人困惑的是,由于预处理器已将头文件包含在包含函数的代码中,因此链接器链接到汇编器/编译器生成的目标文件的库函数是什么?部分混淆主要是由于我对头文件和库之间的差异的无知而产生的。

After a bit of googling, and stack-overflowing (is that the term? :p), I gathered that the header file mostly contains the function declarations whereas the actual implementation is in another binary file called the library (I am still not 100% sure about this).

经过一段谷歌搜索和堆栈溢出(就是术语?:p),我收集到头文件主要包含函数声明,而实际的实现是在另一个称为库的二进制文件中(我仍然不是100%确定这个)。

So, suppose in the following program:-

所以,假设在以下程序中: -

#include<stdio.h>
int main()
{
      printf("whatever");
      return 0;
}

The preprocessor includes the contents of the header file in the code. The compiler/compiler+assembler does its work, and then finally linker combines this object file with another object file which actually has stored the way printf() works.

预处理器在代码中包含头文件的内容。编译器/编译器+汇编器完成其工作,然后最终链接器将此目标文件与另一个实际存储了printf()工作方式的目标文件组合在一起。

Am I correct in my understanding? I may be way off...so could you please help me?

我的理解是否正确?我可能会离开......你能帮我吗?

Edit: I have always wondered about the C++ STL. It always confused me as to what it exactly is, a collection of all those headers or what? Now after reading the responses, can I say that STL is an object file/something that resembles an object file?

编辑:我一直想知道C ++ STL。它总是让我困惑的是它究竟是什么,所有这些标题的集合或什么?在阅读完回复之后,我可以说STL是一个目标文件/类似于目标文件的东西吗?

And also, I thought where I could read the function definitions of functions like pow(), sqrt() etc etc. I would open the header files and not find anything. So, is the function definition in the library in binary unreadable form?

而且,我想在哪里可以读取函数的函数定义,如pow(),sqrt()等等。我会打开头文件,但没有找到任何东西。那么,库中的函数定义是否是二进制不可读的形式?

3 个解决方案

#1


12  

A C source file goes through two main stages, (1) the preprocessor stage where the C source code is processed by the preprocessor utility which looks for preprocessor directives and performs those actions and (2) the compilation stage where the processed C source code is then actually compiled to produce object code files.

AC源文件经历两个主要阶段,(1)预处理器阶段,其中C源代码由预处理器实用程序处理,其寻找预处理器指令并执行那些动作;以及(2)编译阶段,其中处理的C源代码是实际编译生成目标代码文件。

The preprocessor is a utility that does text manipulation. It takes as input a file that contains text (usually C source code) that may contain preprocessor directives and outputs a modified version of the file by applying any directives found to the text input to generate a text output.

预处理器是一个执行文本操作的实用程序。它将包含文本(通常为C源代码)的文件作为输入,该文件可能包含预处理程序指令,并通过应用找到文本输入的任何指令来输出文件的修改版本以生成文本输出。

The file does not have to be C source code because the preprocessor is doing text manipulation. I have seen the C Preprocssor used to extend the make utility by allowing preprossor directives to be included in a make file. The make file with the C Preprocessor directives is run through the C Preprocessor utility and the resulting output then fed into make to do the actual build of the make target.

该文件不必是C源代码,因为预处理器正在进行文本操作。我已经看到C Preprocssor用于扩展make实用程序,允许将preprossor指令包含在make文件中。带有C预处理程序指令的make文件通过C预处理程序实用程序运行,然后生成的输出结果输入make以执行make目标的实际构建。

Libraries and linking

图书馆和链接

A library is a file that contains object code of various functions. It is a way to package the output from several source files when they are compiled into a single file. Many times a library file is provided along with a header file (include file), typically with a .h file extension. The header file contains the function declarations, global variable declarations, as well as preprocessor directives needed for the library. So to use the library, you include the header file provided using the #include directive and you link with the library file.

库是包含各种功能的目标代码的文件。这是一种在将多个源文件编译成单个文件时将其输出打包的方法。很多时候提供库文件以及头文件(包含文件),通常具有.h文件扩展名。头文件包含函数声明,全局变量声明以及库所需的预处理程序指令。因此,要使用该库,您需要包含使用#include指令提供的头文件,并链接到库文件。

A nice feature of a library file is that you are providing the compiled version of your source code and not the source code itself. On the other hand since the library file contains compiled source code, the compiler used to generate the library file must be compatible with the compiler being used to compile your own source code files.

库文件的一个很好的特性是您提供源代码的编译版本而不是源代码本身。另一方面,由于库文件包含已编译的源代码,因此用于生成库文件的编译器必须与用于编译自己的源代码文件的编译器兼容。

There are two types of libraries commonly used. The first and older type is the static library. The second and more recent is the dynamic library (Dynamic Link Library or DLL in Windows and Shared Library or SO in Linux). The difference between the two is when the functions in the library are bound to the executable that is using the library file.

通常使用两种类型的库。第一个和更旧的类型是静态库。第二个也是最近的是动态库(Windows中的动态链接库或DLL和共享库中的DLL或Linux中的SO)。两者之间的区别在于库中的函数绑定到使用库文件的可执行文件。

The linker is a utility that takes the various object files and library files to create the executable file. When an external or global function or variable is used the C source file, a kind of marker is used to tell the linker that the address of the function or variable needs to be inserted at that point.

链接器是一个实用程序,它使用各种目标文件和库文件来创建可执行文件。当外部或全局函数或变量用于C源文件时,使用一种标记来告诉链接器需要在该点插入函数或变量的地址。

The C compiler only knows what is in the source it compiles and does not know what is in other files such as object files or libraries. So the linker's job is to take the various object files and libraries and to make the final connections between parts by replacing the markers with actual connections. So a linker is a utility that "links" together the various components, replacing the marker for a global function or variable in the object files and libraries with a link to the actual object code that was generated for that global function or variable.

C编译器只知道它编译的源代码中的内容,并且不知道其他文件(例如目标文件或库)中的内容。因此,链接器的工作是获取各种目标文件和库,并通过用实际连接替换标记来在部件之间建立最终连接。因此,链接器是一个实用程序,它将各个组件“链接”在一起,用目标文件和库中的全局函数或变量替换标记,并指向为该全局函数或变量生成的实际目标代码的链接。

During the linker stage is when the difference between a static library and a dynamic or shared library becomes evident. When a static library is used, the actual object code of the library is included in the application executable. When a dynamic or shared library is used, the object code included in the application executable is code to find the shared library and connect with it when the application is run.

在链接器阶段期间,静态库与动态或共享库之间的差异变得明显。使用静态库时,库的实际目标代码包含在应用程序可执行文件中。使用动态或共享库时,应用程序可执行文件中包含的目标代码是用于查找共享库的代码,并在运行应用程序时与其连接。

In some cases the same global function name may be used in several different object files or libraries so the linker will normally just use the first one it comes across and issue a warning about others found.

在某些情况下,可以在几个不同的目标文件或库中使用相同的全局函数名称,因此链接器通常只使用它遇到的第一个并发出有关其他文件的警告。

Summary of compile and link

编译和链接摘要

So the basic process for a compile and link of a C program is:

因此,编译和链接C程序的基本过程是:

  • preprocessor utility generates the C source to be compiled

    预处理器实用程序生成要编译的C源

  • compiler compiles the C source into object code generating a set of object files

    编译器将C源编译为生成一组目标文件的目标代码

  • linker links the various object files along with any libraries into executable file

    链接器将各种目标文件以及任何库链接到可执行文件中

The above is the basic process however when using dynamic libraries it can get more complicated especially if part of the application being generated has dynamic libraries that it is generating.

以上是基本过程,但是当使用动态库时,它会变得更复杂,特别是如果生成的应用程序的一部分具有它正在生成的动态库。

The loader

There is also the stage of when the application is actually loaded into memory and execution starts. An operating system provides a utility, the loader, which reads the application executable file and loads it into memory and then starts the application running. The starting point or entry point for the executable is specified in the executable file so after the loader reads the executable file into memory it will then start the executable running by jumping to the entry point memory address.

还有应用程序实际加载到内存并开始执行的阶段。操作系统提供一个实用程序,即加载器,它读取应用程序可执行文件并将其加载到内存中,然后启动应用程序运行。可执行文件的起始点或入口点在可执行文件中指定,因此在加载程序将可执行文件读入内存后,它将通过跳转到入口点内存地址来启动可执行文件。

One problem the linker can run into is that sometimes it may come across a marker when it is processing the object code files that requires an actual memory address. However the linker does not know the actual memory address because the address will vary depending on where in memory the application is loaded. So the linker marks that as something for the loader utility to fix when the loader is loading the executable into memory and getting ready to start it running.

链接器可能遇到的一个问题是,有时它在处理需要实际内存地址的目标代码文件时可能遇到标记。但是,链接器不知道实际的内存地址,因为地址将根据加载应用程序的内存位置而有所不同。因此,当加载程序将可执行文件加载到内存并准备启动它运行时,链接器会将此标记为装入器实用程序修复的内容。

With modern CPUs with hardware supported virtual address to physical address mapping or translation, this issue of actual memory address is seldom a problem. Each application is loaded at the same virtual address and the hardware address translation deals with the actual, physical address. However older CPUs or lower cost CPUs such as micro-controllers that are lacking the memory management unit (MMU) hardware support for address translation still need this issue addressed.

对于具有硬件支持的虚拟地址到物理地址映射或转换的现代CPU,这个实际存储器地址问题很少成为问题。每个应用程序都加载到同一个虚拟地址,硬件地址转换处理实际的物理地址。然而,较旧的CPU或较低成本的CPU(例如缺少用于地址转换的存储器管理单元(MMU)硬件支持的微控制器)仍然需要解决该问题。

Entry points and the C Runtime

入口点和C运行时

A final topic is the C Runtime and the main() and the executable entry point.

最后一个主题是C Runtime以及main()和可执行入口点。

The C Runtime is object code provided by the compiler manufacturer that contains the entry point for an application that is written in C. The main() function is the entry point provided by the programmer writing the application however this is not the entry point that the loader sees. The main() function is called by the C Runtime after the application is started and the C Runtime code sets up the environment for the application.

C Runtime是由编译器制造商提供的目标代码,它包含用C编写的应用程序的入口点.main()函数是编写应用程序的程序员提供的入口点但是这不是入口点。装载机见。在应用程序启动后,C运行时调用main()函数,C运行时代码为应用程序设置环境。

The C Runtime is not the Standard C Library. The purpose of the C Runtime is to manage the runtime environment for the application. The purpose of the Standard C Library is to provide a set of useful utility functions so that a programmer doesn't have to create their own.

C运行时不是标准C库。 C运行时的目的是管理应用程序的运行时环境。标准C库的目的是提供一组有用的实用程序函数,以便程序员不必创建自己的函数。

When the loader loads the application and jumps to the entry point provided by the C Runtime, the C Runtime then performs the various initialization actions needed to provide the proper runtime environment for the application. Once this is done, the C Runtime then calls the main() function so that the code created by the application developer or programmer starts to run. When the main() returns or when the exit() function is called, the C Runtime performs any actions needed to clean up and close out the application.

当加载程序加载应用程序并跳转到C运行时提供的入口点时,C运行时将执行为应用程序提供正确的运行时环境所需的各种初始化操作。完成此操作后,C Runtime将调用main()函数,以便应用程序开发人员或程序员创建的代码开始运行。当main()返回或调用exit()函数时,C运行时执行清理和关闭应用程序所需的任何操作。

#2


3  

This is an extremely common source of confusion. I think the easiest way to understand what's happening is to take a simple example. Forget about libraries for a moment and consider the following:

这是一个非常常见的混乱来源。我认为理解正在发生的事情最简单的方法就是举一个简单的例子。暂时忘掉图书馆并考虑以下内容:

$ cat main.c
extern int foo( void );
int main( void ) { return foo(); }
$ cat foo.c
int foo( void ) { return 0; }
$ cc -c main.c
$ cc -c foo.c
$ cc main.o foo.o

The declaration extern int foo( void ) is performing exactly the same function as the header file of a library. foo.o is performing the function of the library. If you understand this example, and why neither cc main.c nor cc main.o work, then you understand the difference between header files and libraries.

声明extern int foo(void)执行的功能与库的头文件完全相同。 foo.o正在执行库的功能。如果你理解这个例子,为什么cc main.c和cc main.o都不起作用,那么你就能理解头文件和库之间的区别。

#3


2  

Yes, almost correct. Except that the linker does not links object files, but also libraries - in thise case, it's the C standard library (libc) is what is linked to your object file. The rest of your assumptions appear to be true about the compilation stages + difference between a header and a library.

是的,几乎正确。除了链接器不链接目标文件,还链接库 - 在这种情况下,它是C标准库(libc)链接到您的目标文件。关于编译阶段+标题和库之间的差异,其余的假设似乎都是正确的。

#1


12  

A C source file goes through two main stages, (1) the preprocessor stage where the C source code is processed by the preprocessor utility which looks for preprocessor directives and performs those actions and (2) the compilation stage where the processed C source code is then actually compiled to produce object code files.

AC源文件经历两个主要阶段,(1)预处理器阶段,其中C源代码由预处理器实用程序处理,其寻找预处理器指令并执行那些动作;以及(2)编译阶段,其中处理的C源代码是实际编译生成目标代码文件。

The preprocessor is a utility that does text manipulation. It takes as input a file that contains text (usually C source code) that may contain preprocessor directives and outputs a modified version of the file by applying any directives found to the text input to generate a text output.

预处理器是一个执行文本操作的实用程序。它将包含文本(通常为C源代码)的文件作为输入,该文件可能包含预处理程序指令,并通过应用找到文本输入的任何指令来输出文件的修改版本以生成文本输出。

The file does not have to be C source code because the preprocessor is doing text manipulation. I have seen the C Preprocssor used to extend the make utility by allowing preprossor directives to be included in a make file. The make file with the C Preprocessor directives is run through the C Preprocessor utility and the resulting output then fed into make to do the actual build of the make target.

该文件不必是C源代码,因为预处理器正在进行文本操作。我已经看到C Preprocssor用于扩展make实用程序,允许将preprossor指令包含在make文件中。带有C预处理程序指令的make文件通过C预处理程序实用程序运行,然后生成的输出结果输入make以执行make目标的实际构建。

Libraries and linking

图书馆和链接

A library is a file that contains object code of various functions. It is a way to package the output from several source files when they are compiled into a single file. Many times a library file is provided along with a header file (include file), typically with a .h file extension. The header file contains the function declarations, global variable declarations, as well as preprocessor directives needed for the library. So to use the library, you include the header file provided using the #include directive and you link with the library file.

库是包含各种功能的目标代码的文件。这是一种在将多个源文件编译成单个文件时将其输出打包的方法。很多时候提供库文件以及头文件(包含文件),通常具有.h文件扩展名。头文件包含函数声明,全局变量声明以及库所需的预处理程序指令。因此,要使用该库,您需要包含使用#include指令提供的头文件,并链接到库文件。

A nice feature of a library file is that you are providing the compiled version of your source code and not the source code itself. On the other hand since the library file contains compiled source code, the compiler used to generate the library file must be compatible with the compiler being used to compile your own source code files.

库文件的一个很好的特性是您提供源代码的编译版本而不是源代码本身。另一方面,由于库文件包含已编译的源代码,因此用于生成库文件的编译器必须与用于编译自己的源代码文件的编译器兼容。

There are two types of libraries commonly used. The first and older type is the static library. The second and more recent is the dynamic library (Dynamic Link Library or DLL in Windows and Shared Library or SO in Linux). The difference between the two is when the functions in the library are bound to the executable that is using the library file.

通常使用两种类型的库。第一个和更旧的类型是静态库。第二个也是最近的是动态库(Windows中的动态链接库或DLL和共享库中的DLL或Linux中的SO)。两者之间的区别在于库中的函数绑定到使用库文件的可执行文件。

The linker is a utility that takes the various object files and library files to create the executable file. When an external or global function or variable is used the C source file, a kind of marker is used to tell the linker that the address of the function or variable needs to be inserted at that point.

链接器是一个实用程序,它使用各种目标文件和库文件来创建可执行文件。当外部或全局函数或变量用于C源文件时,使用一种标记来告诉链接器需要在该点插入函数或变量的地址。

The C compiler only knows what is in the source it compiles and does not know what is in other files such as object files or libraries. So the linker's job is to take the various object files and libraries and to make the final connections between parts by replacing the markers with actual connections. So a linker is a utility that "links" together the various components, replacing the marker for a global function or variable in the object files and libraries with a link to the actual object code that was generated for that global function or variable.

C编译器只知道它编译的源代码中的内容,并且不知道其他文件(例如目标文件或库)中的内容。因此,链接器的工作是获取各种目标文件和库,并通过用实际连接替换标记来在部件之间建立最终连接。因此,链接器是一个实用程序,它将各个组件“链接”在一起,用目标文件和库中的全局函数或变量替换标记,并指向为该全局函数或变量生成的实际目标代码的链接。

During the linker stage is when the difference between a static library and a dynamic or shared library becomes evident. When a static library is used, the actual object code of the library is included in the application executable. When a dynamic or shared library is used, the object code included in the application executable is code to find the shared library and connect with it when the application is run.

在链接器阶段期间,静态库与动态或共享库之间的差异变得明显。使用静态库时,库的实际目标代码包含在应用程序可执行文件中。使用动态或共享库时,应用程序可执行文件中包含的目标代码是用于查找共享库的代码,并在运行应用程序时与其连接。

In some cases the same global function name may be used in several different object files or libraries so the linker will normally just use the first one it comes across and issue a warning about others found.

在某些情况下,可以在几个不同的目标文件或库中使用相同的全局函数名称,因此链接器通常只使用它遇到的第一个并发出有关其他文件的警告。

Summary of compile and link

编译和链接摘要

So the basic process for a compile and link of a C program is:

因此,编译和链接C程序的基本过程是:

  • preprocessor utility generates the C source to be compiled

    预处理器实用程序生成要编译的C源

  • compiler compiles the C source into object code generating a set of object files

    编译器将C源编译为生成一组目标文件的目标代码

  • linker links the various object files along with any libraries into executable file

    链接器将各种目标文件以及任何库链接到可执行文件中

The above is the basic process however when using dynamic libraries it can get more complicated especially if part of the application being generated has dynamic libraries that it is generating.

以上是基本过程,但是当使用动态库时,它会变得更复杂,特别是如果生成的应用程序的一部分具有它正在生成的动态库。

The loader

There is also the stage of when the application is actually loaded into memory and execution starts. An operating system provides a utility, the loader, which reads the application executable file and loads it into memory and then starts the application running. The starting point or entry point for the executable is specified in the executable file so after the loader reads the executable file into memory it will then start the executable running by jumping to the entry point memory address.

还有应用程序实际加载到内存并开始执行的阶段。操作系统提供一个实用程序,即加载器,它读取应用程序可执行文件并将其加载到内存中,然后启动应用程序运行。可执行文件的起始点或入口点在可执行文件中指定,因此在加载程序将可执行文件读入内存后,它将通过跳转到入口点内存地址来启动可执行文件。

One problem the linker can run into is that sometimes it may come across a marker when it is processing the object code files that requires an actual memory address. However the linker does not know the actual memory address because the address will vary depending on where in memory the application is loaded. So the linker marks that as something for the loader utility to fix when the loader is loading the executable into memory and getting ready to start it running.

链接器可能遇到的一个问题是,有时它在处理需要实际内存地址的目标代码文件时可能遇到标记。但是,链接器不知道实际的内存地址,因为地址将根据加载应用程序的内存位置而有所不同。因此,当加载程序将可执行文件加载到内存并准备启动它运行时,链接器会将此标记为装入器实用程序修复的内容。

With modern CPUs with hardware supported virtual address to physical address mapping or translation, this issue of actual memory address is seldom a problem. Each application is loaded at the same virtual address and the hardware address translation deals with the actual, physical address. However older CPUs or lower cost CPUs such as micro-controllers that are lacking the memory management unit (MMU) hardware support for address translation still need this issue addressed.

对于具有硬件支持的虚拟地址到物理地址映射或转换的现代CPU,这个实际存储器地址问题很少成为问题。每个应用程序都加载到同一个虚拟地址,硬件地址转换处理实际的物理地址。然而,较旧的CPU或较低成本的CPU(例如缺少用于地址转换的存储器管理单元(MMU)硬件支持的微控制器)仍然需要解决该问题。

Entry points and the C Runtime

入口点和C运行时

A final topic is the C Runtime and the main() and the executable entry point.

最后一个主题是C Runtime以及main()和可执行入口点。

The C Runtime is object code provided by the compiler manufacturer that contains the entry point for an application that is written in C. The main() function is the entry point provided by the programmer writing the application however this is not the entry point that the loader sees. The main() function is called by the C Runtime after the application is started and the C Runtime code sets up the environment for the application.

C Runtime是由编译器制造商提供的目标代码,它包含用C编写的应用程序的入口点.main()函数是编写应用程序的程序员提供的入口点但是这不是入口点。装载机见。在应用程序启动后,C运行时调用main()函数,C运行时代码为应用程序设置环境。

The C Runtime is not the Standard C Library. The purpose of the C Runtime is to manage the runtime environment for the application. The purpose of the Standard C Library is to provide a set of useful utility functions so that a programmer doesn't have to create their own.

C运行时不是标准C库。 C运行时的目的是管理应用程序的运行时环境。标准C库的目的是提供一组有用的实用程序函数,以便程序员不必创建自己的函数。

When the loader loads the application and jumps to the entry point provided by the C Runtime, the C Runtime then performs the various initialization actions needed to provide the proper runtime environment for the application. Once this is done, the C Runtime then calls the main() function so that the code created by the application developer or programmer starts to run. When the main() returns or when the exit() function is called, the C Runtime performs any actions needed to clean up and close out the application.

当加载程序加载应用程序并跳转到C运行时提供的入口点时,C运行时将执行为应用程序提供正确的运行时环境所需的各种初始化操作。完成此操作后,C Runtime将调用main()函数,以便应用程序开发人员或程序员创建的代码开始运行。当main()返回或调用exit()函数时,C运行时执行清理和关闭应用程序所需的任何操作。

#2


3  

This is an extremely common source of confusion. I think the easiest way to understand what's happening is to take a simple example. Forget about libraries for a moment and consider the following:

这是一个非常常见的混乱来源。我认为理解正在发生的事情最简单的方法就是举一个简单的例子。暂时忘掉图书馆并考虑以下内容:

$ cat main.c
extern int foo( void );
int main( void ) { return foo(); }
$ cat foo.c
int foo( void ) { return 0; }
$ cc -c main.c
$ cc -c foo.c
$ cc main.o foo.o

The declaration extern int foo( void ) is performing exactly the same function as the header file of a library. foo.o is performing the function of the library. If you understand this example, and why neither cc main.c nor cc main.o work, then you understand the difference between header files and libraries.

声明extern int foo(void)执行的功能与库的头文件完全相同。 foo.o正在执行库的功能。如果你理解这个例子,为什么cc main.c和cc main.o都不起作用,那么你就能理解头文件和库之间的区别。

#3


2  

Yes, almost correct. Except that the linker does not links object files, but also libraries - in thise case, it's the C standard library (libc) is what is linked to your object file. The rest of your assumptions appear to be true about the compilation stages + difference between a header and a library.

是的,几乎正确。除了链接器不链接目标文件,还链接库 - 在这种情况下,它是C标准库(libc)链接到您的目标文件。关于编译阶段+标题和库之间的差异,其余的假设似乎都是正确的。