如何将头文件编译为可执行文件

How is a header file being compiled into the executable file?

本文关键字:编译 可执行文件 文件      更新时间:2023-10-16

当您包含来自 C 标准库或 C++ STL 的头文件(.h、.hpp、.hh、.hxx 扩展名)(甚至包括像 windows.h 这样的Microsoft大文件)并且仅使用其中一定数量的有限函数时,整个文件是变成二进制文件并复制到可执行文件中,还是只是特定的, 正在使用的相关函数变为二进制?

如果整个文件被复制(这就是我认为实际发生的情况,因为windows.h具有宏定义以减少冗余; 例如WIN32_LEAN_AND_MEAN) - 为什么会这样发生?为什么#include预处理器命令不只复制使用的函数(以及这些函数在后台使用的其他函数)?不是更划算吗?

如果只复制相关函数 - 为什么我们必须首先进行标头包含?为什么我们不在需要时使用和编译大量的函数,就像 PHP 等解释型语言中的情况(以及 Python 中的某些情况)一样。如果只是因为"C和C++比较旧,已经标准化",为什么不在他们的新版本中这样做呢?或者至少现代编译器允许它(我们已经看到编译器弯曲老化语言以支持现代开发人员的情况)?

头文件只是告诉编译器外部函数和变量的类型,定义宏,类型等。什么都不会被复制。在源文件中引用的任何函数和变量(称为外部符号)都将在链接器阶段链接。

如果包含 stdio.h 并在程序中使用 printf,编译器会将 printf 添加为目标文件中的"未解析"符号,然后链接器将尝试在显式链接的对象文件中或配置为搜索的库中查找名为 printf 的函数。

如前所述,#including 文件和将该文件的内容复制到源文件中之间没有真正的区别。如果包含的文件包含函数或数据定义(不仅仅是声明),则这些 DO 将成为目标文件的一部分。

将编译整个标头(除了受 #if#ifdef 等保护的部分,以防止它)。

由于通常在 C 中完成操作,标头仅包含声明而不是定义,宏除外。因此,编译标头主要是将名称放入编译器的符号表中,而不生成任何代码。

在C++中,标头通常包含实际定义,尤其是在使用模板时。在这种情况下,标头可能包含许多内联函数定义以及类定义和各种声明。

这并不意味着整个内容最终都会出现在最终的可执行文件中。现代链接器可以合并同一对象/函数的多个定义,并消除未使用的部分。

WIN32_LEAN_AND_MEAN这样的宏的发明主要是为了缩短编译时间。它们通常对最终可执行文件的大小影响很小或没有影响。

头文件不是由编译器直接读取的,而是由预处理器读取的,预处理器基本上将其直接复制到 #include 指令的位置。

由于大多数头文件不包含任何实际代码,只包含声明和宏,因此实际上没有真正放入可执行文件的此类头文件。所有宏和递归#include指令都由预处理器解析。留给编译器的是声明、类型别名(typedef声明)和更多的声明。声明实际上并不生成任何代码,它们仅由编译器在解析和生成实际代码时用于其内部状态。

您可能希望了解 C 预处理器。

根据我的经验,头文件与文件大小几乎没有关系,因为几乎所有操作系统都内置了 c 或 c++,因此没有必要复制二进制文件。

标头

对文件大小产生影响的唯一情况是您制作的标头。WIN32_LEAN_AND_MEAN用于排除头文件中几乎从未使用过的服务。

如果您想了解更多信息,我还找到了另一篇Stack Overflow文章。