5

当我的 cpp 文件用于#include添加一些标题时,我的最终程序的大小会变大吗?头文件不被视为编译单元,但是头文件的内容是由预处理器添加到实际源文件中的,那么输出文件(exe或dll)的大小会受此影响吗?

编辑:我忘了提到问题不在于模板/内联函数。我的意思是如果我放置一个#include没有任何函数实现细节的标头会发生什么。谢谢。

4

8 回答 8

13

这取决于内容以及编译器的实现方式。如果您在标头中不使用任何内容,您的编译器很可能会足够聪明,不会将任何内容添加到您的可执行文件中。

但是,我不会指望这一点。我知道在 VC++ 的 6 天里,我们发现仅仅 #include Windows.h 为每个执行它的源文件添加了 64K 到可执行文件中。

于 2009-10-08T18:31:38.637 回答
7

你澄清说:

[标题没有] 模板/内联函数...没有任何函数的实现细节。

一般来说,不会,添加头文件不会影响程序大小。

你可以测试一下。取一个已经构建的程序,并检查可执行文件的大小。然后进入每个 .cpp 文件并包含该文件中实际不需要的标准 C 或 C++ 头文件。构建程序并再次检查可执行文件的大小 - 它应该与以前的大小相同。

总的来说,影响可执行文件大小的唯一因素是那些导致编译器生成不同数量的代码、全局/静态变量初始化或 DLL/共享库使用的因素。即使这样,如果程序运行不需要任何此类项目,大多数现代链接器都会将这些东西扔掉。

因此,包括仅包含函数原型、没有内联的类/结构定义以及枚举定义等内容的头文件不应改变任何内容。

但是,当然也有例外。这里有几个。

一个是如果你有一个简单的链接器。然后,如果您添加一个生成程序实际上不需要的东西的头文件,并且链接器没有将它们扔掉,那么可执行文件的大小将会膨胀。(有些人故意以这种方式构建链接器,因为链接时间会变得异常快。)

很多时候,添加一个添加或更改预处理器符号定义的头文件会改变编译器生成的内容。例如,assert.h(或 cassert)定义了 assert() 宏。如果您在 .c/.cpp 文件中包含更改 NDEBUG 预处理器符号定义的头文件,它将更改 assert() 用法是否生成任何代码,从而更改可执行文件大小。

此外,添加更改编译器选项的头文件将更改可执行文件大小。例如,许多编译器允许您通过#pragma pack行之类的方式更改结构的默认“打包”。因此,如果您在 .c/.cpp 文件中添加更改结构打包的头文件,编译器将生成不同的代码来处理结构,从而更改可执行文件大小。

正如其他人指出的那样,当您处理 Visual C++/Visual Studio 时,所有的赌注都没有了。容我们说,微软对他们的开发工具有一个独特的视角,这是在其他平台上编写编译器系统的人所没有的。

于 2009-10-08T19:49:52.597 回答
1

使用现代编译器包含的文件仅在它们包含静态数据或使用其中定义的普通或内联函数时才会影响二进制文件的大小。

于 2009-10-08T18:32:47.793 回答
0

你也可以在头文件中定义全局变量(虽然我不推荐它)。如果你这样做了,你应该用#ifdef/#end 块包围它们,这样它们就不会在多个编译单元中定义(否则链接器会抱怨)。无论如何,这会增加程序的大小。

于 2009-10-08T18:30:13.040 回答
0

是的,因为例如可以在头文件中定义内联函数,并且当您调用这些函数时,这些内联函数的代码当然会添加到您的程序代码中。模板实例化也将被添加到您的程序代码中。

于 2009-10-08T18:26:58.507 回答
0

对于完全是声明性的标题(通常应该是),不。然而,预处理器和编译器必须花时间来解析头文件,因此头文件会增加编译时间;特别是大且嵌套较深的,例如 - 这就是为什么一些编译器使用“预编译头文件”的原因。

即使是内联和模板代码也不会直接增加代码大小。如果模板从未实例化或未调用内联函数,则不会生成代码。但是,如果它被调用/实例化,代码大小会迅速增长。如果编译器实际上内联代码(编译器没有义务这样做,而且大多数人都没有这样做,除非被迫这样做),代码重复可能很重要。即使它没有被编译器真正内联,它仍然在每个引用它的目标模块 - 它需要一个智能链接器来删除重复项,这不是给定的 - 如果使用不同的选项编译单独的目标文件,来自同一源的内联代码可能不会在每个目标文件中生成相同的代码,所以会甚至不能被复制。在模板的情况下,将为调用的每种类型创建单独的实例化。

于 2009-10-08T20:00:05.353 回答
0

请记住,#define句子可以在编译时将代码膨胀成一个巨大但功能强大的编译文件。

于 2009-10-08T20:04:13.317 回答
0

最好将文件中的#include 限制为必要的。除了影响可执行文件大小之外,拥有额外的#includes 会导致更大的编译时依赖项列表,如果您更改常用的#included 头文件,这将增加您的构建时间。

于 2009-10-08T20:21:48.820 回答