多次包含头文件会导致编译时间更长?

发布于 2024-11-30 14:10:52 字数 351 浏览 3 评论 0原文

多次包含相同的头文件是否会增加编译时间?

例如,假设我的项目中的每个文件都使用 ;。如果我在源代码中包含很多文件,那么会增加编译时间吗?

我一直认为保护标头起到了避免双重定义的重要作用,但作为副产品也消除了双重代码。

事实上,我认识的一个人提出了一些想法来消除这种多重包含。然而,我认为它们完全违背了 C++ 中的良好设计实践。但仍然想知道他建议改变的原因可能是什么?

Does including the same header files multiple times increase the compilation time?

For example, suppose every file in my project uses <iostream> <string> <vector> and <algorithm>. And if I include a lot of files in my source code, then does that increase the compile time?

I always thought that the guard headers served important purpose of avoiding double definitions but as a by product also eliminates double code.

Actually, someone I know proposed some ideas to remove such multiple inclusions. However, I consider them to be completely against the good design practices in c++. But was still wondering what might be the reasons of him to suggest the changes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

你的背包 2024-12-07 14:10:52

这些答案中的大多数都是错误的......对于现代编译器,假设标头使用通常的“包含保护”习惯用法,则多次包含同一文件的开销为零

例如,GCC 预处理器有特殊的代码来识别包含保护习惯用法。它甚至不会打开第二个和后续 #include 指令的头文件(更不用说读取它)。

我不确定其他编译器,但如果它们中的大多数没有实现相同的优化,我会感到非常惊讶。

Most of these answers are wrong... For modern compilers, there is zero overhead for including the same file multiple times, assuming the header uses the usual "include guard" idiom.

The GCC preprocessor, for example, has special code to recognize the include guard idiom. It will not even open the header file (never mind reading it) for the second and subsequent #include directives.

I am not sure about other compilers, but I would be very surprised if most of them did not implement the same optimization.

秋叶绚丽 2024-12-07 14:10:52

除了预编译头之外的另一种技术是编译器防火墙习惯用法,解释如下:

http://www.gotw.ca /publications/mill04.htm

http://www.gotw.ca/publications/mill05.htm

Another technique besides precompiled headers is the compiler firewall idiom, explained here:

http://www.gotw.ca/publications/mill04.htm

http://www.gotw.ca/publications/mill05.htm

旧情勿念 2024-12-07 14:10:52

每次源文件中出现 #include 时,都必须沿着包含路径找到并读取“something.h”。但是有#ifndef _SOMETHING_H_检查,所以这样的something.h的内容不会被编译。
因此存在一些开销,但它确实很小。

Every time #include <something.h> occurs in your source file, 'something.h' have to be found along the include path and read. But there is #ifndef _SOMETHING_H_ check, so the content of such something.h would not be compiled.
Thus there is some overhead, but it is really small.

云柯 2024-12-07 14:10:52

如果编译时间是一个问题,人们过去常常使用 Praetorian 推荐的优化,最初在 大规模软件设计。然而,大多数现代编译器会自动针对这种情况进行优化。例如,请参阅gcc 的帮助

If compile times were an issue, people used to use the optimisation recommended by Praetorian, originally recommened in Large Scale Software Design. However, most modern compilers automatically optimise for this case. For example, see the help from gcc

感性不性感 2024-12-07 14:10:52

最好的方法是使用预编译头。我不知道你使用的是哪个编译器,但大多数都有这个功能。我建议您参考编译器手册以了解如何实现这一目标。

它基本上收集所有头文件并将其编译成目标文件,然后可供链接器使用。这大大加快了编译速度。

小缺点:

您需要有 1 个“uberheader”,它包含在每个编译单元 (.cpp) 中。

在该 uberheader 中,仅包含库中的静态标头,而不包含您自己的静态标头。那么编译器就不需要经常重新编译它。

它有帮助,特别是。当使用仅头文件库(例如 boost 或 glm、eigen 等)时。

HTH

The best is to use precompiled headers. I do not know which compiler you are using, but most of them have this feature. I suggest you to refer to your compiler-manual on how to achieve this.

It basically collects all headerfiles and compiles it into a object file which then can be used by the linker. That speeds up compiling very much.

Minor Drawback:

You need to have 1 "uberheader" which is included in every compilation-unit (.cpp).

In that uberheader, only include static headers from libraries, not your own. Then the compiler does not need to recompile it very often.

It helps esp. when using header-only libraries such as boost or glm, eigen etc.

HTH

嘿哥们儿 2024-12-07 14:10:52

是的,多次包含相同的标头意味着需要在预处理器防护启动并阻止多个定义之前打开文件。 Mozilla 源代码使用以下技巧来防止这种情况:

Foo.h

#ifndef FOO_H
#define FOO_H

// whatever

#endif  /* FOO_H */

在所有需要包含 foo.h 的文件中

#ifndef FOO_H
#include "foo.h"
#endif

这可以防止 foo.h 必须被多次打开。当然,这取决于每个人都遵循其预处理器防护的特定命名约定。

您无法使用标准标头执行此操作,因为它们的预处理器防护没有通用的命名约定。

编辑:
再次阅读您的问题后,我认为您是在询问不同源文件中包含相同的标头。我上面所说的对此没有帮助。每个头文件仍然必须在每个翻译单元中至少打开并包含一次。我知道防止这种情况发生的唯一方法是使用预编译头,正如 @scorcher24 在他的回答中提到的那样。但我会远离这个解决方案,因为没有跨编译器生成预编译头的标准方法,除非编译时间绝对令人望而却步。

Yes, including the same header multiple times means that the file needs to be opened before the preprocessor guards kick in and prevent multiple definitions. The Mozilla source code uses the following trick to prevent this:

Foo.h

#ifndef FOO_H
#define FOO_H

// whatever

#endif  /* FOO_H */

In all files that need to include foo.h

#ifndef FOO_H
#include "foo.h"
#endif

This prevents foo.h from having to be opened multiple times. Of course, this depends on everyone following a particular naming convention for their preprocessor guards.

You can't do this with standard headers, since there is no common naming convention for their preprocessor guards.

EDIT:
After reading your question again, I think you're asking about the same header being included in different source files. What I talked about above does not help with that. Each header file will still have to be opened and included at least once in every translation unit. The only way I know of to prevent this is to use precompiled headers, as @scorcher24 mentioned in his answer. But I'd stay away from this solution, because there is no standard way of generating precompiled headers across compilers, unless the compile times are absolutely prohibitive.

计㈡愣 2024-12-07 14:10:52

某些编译器(尤其是 Microsoft 的编译器)具有 #pragma Once 指令,您可以使用该指令在包含文件已被包含后自动跳过该包含文件。这消除了任何性能损失。

http://en.wikipedia.org/wiki/Pragma_once

Some compilers, most notably Microsoft's, have a #pragma once directive that you can use to automatically skip an include file once it's already been included. This removes any performance penalty.

http://en.wikipedia.org/wiki/Pragma_once

风轻花落早 2024-12-07 14:10:52

这可能是一个问题。正如其他人所说,大多数现代编译器
智能地处理案件,并且只会在以下位置重新打开文件
退化病例。然而,大多数并不是全部,而且是主要的之一
微软是个例外,它确实得到了很多人的支持。这
最可靠的解决方案(如果这确实是您环境中的问题)是
使用 Lakos 约定,将包含守卫放在
#include 以及标头中。当然,这意味着一个标准
生成守卫名称的约定。 (对于外部包含,将
它们位于您自己的标头中,这尊重您当地的惯例。)
或者,您可以同时使用防护和#pragma Once。这
守卫将始终起作用,并且大多数编译器将避免额外的打开,
#pragma Once 通常会避免与 Microsoft 的额外打开。
#pragma Once 在复杂的网络中无法可靠地实现
情况,但只要所有文件都位于本地驱动器上,
这是相当可靠的。)

It can be an issue. As others have said, most modern compilers
handle the case intelligently, and will only re-open the file in
degenerate cases. Most is not all, however, and one of the major
exceptions is Microsoft, which a lot of people do have to support. The
surest solution (if this is really a problem in your environment) is to
use the Lakos convention, putting the include guards around the
#include as well as in the header. This means, of course, a standard
convention for generating the guard names. (For external includes, wrap
them in your own header, which respects your local convention.)
Alternatively, you can use both the guards and #pragma once. The
guards will always work, and most compilers will avoid the extra opens,
and #pragma once will usually avoid the extra opens with Microsoft.
(#pragma once cannot be implemented reliably in complex networked
situation, but as long as all of your files are on your local drive,
it's quite reliable.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文