C++中的#include <bits/stdc++.h>如何工作?

168

我从一篇Codeforces博客中了解到,如果在一个C++程序中添加#include <bits/stdc++.h>,那么就不需要再包含其他任何头文件。 #include <bits/stdc++.h>如何工作,并且使用它代替单独包含头文件是否可行?


5
很可能这是用于教育目的。我假设 bits/stdc++.h 包含了所有的 C++ 头文件。 - 101010
如果包含一个头文件更快、可移植、简便和更好,那么标准委员会为什么要费心将STL的功能分离到多个头文件中呢?对于上述内容请使用以下翻译:/agree - Marco A.
5
这是一个预编译头文件的实现文件。 - Yuushi
3
因为1980年的计算机内存更少。 - Neil Kirk
70
我用了你提到的那个工具,点开了第一个链接,来到了这个页面,看到了你的评论,然后陷入了一个循环。 - riv
3
很久以前有一个努力,由BS(人名缩写)主导,旨在为新用户和快速玩具构建实现一种基本的厨房水槽标头。但是该计划因某些原因停滞了(是否对于大型实际项目而言不是最佳实践?我还记得他们想要发布和调试具有相同的ABI,但这是行不通的)。虽然我找不到参考文献,但我认为这样的标头确实有其合法的应用领域。不过,在我们使用模块时,这可能会神奇地消失。 - emsr
4个回答

167

这基本上是一个头文件,也包括了所有标准库和STL包含文件。我能看到的唯一目的就是用于测试和教育。

例如,参见 GCC 4.8.0 /bits/stdc++.h source

使用它会包括很多不必要的内容,并增加编译时间。

编辑:正如Neil所说,这是预编译头文件的实现。如果您正确地设置了预编译,它实际上可以加快编译时间,具体取决于您的项目。(https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html

然而,我建议您花时间学习每个sl/stl头文件并单独包含它们,不要使用“超级头文件”,除非是为了预编译。


22
这是为了预编译头文件,可以减少编译时间!(设置正确的情况下) - Neil Kirk
11
我认为完全不知道正在使用的东西定义在哪里学习C ++不是很好。你应该在什么时候停下来弄清楚它呢?(注意:本翻译保留了原句的语法和结构,同时简化了措辞并使之更易懂。) - OJFord
32
最好永远不需要。这是21世纪,编译器应该能够找出我需要的标准库的部分,以节省我编写重要代码的时间。但当然人们应该学习头文件,因为它是语言的一部分。 - Neil Kirk
2
包含它的一个小缺点是会导致命名空间中有很多名称。在极少数情况下,这可能会导致一些难以理解的错误(持续几秒钟)。例如,如果您的变量之一被命名为“count”。但我目前想不到具体的混淆错误示例... - Evgeni Sergeev
1
这个头文件的主要目的是用于编程竞赛。我建议在任何严肃的情境中避免使用它。 - Apollys supports Monica
显示剩余3条评论

52

#include <bits/stdc++.h> 是一个预编译头文件的实现文件。

从软件工程的角度来看,最好尽量减少包含文件。如果你使用 <bits/stdc++.h>,它实际上会包含很多你的程序可能不需要的文件,从而不必要地增加编译时间和程序大小。[编辑:正如@Swordfish在评论中指出,输出程序大小并不受影响。但是,最好只包括你实际需要的库,除非它是一些竞争性比赛]

但在比赛中,使用这个文件是一个好主意,当你想要减少做琐事的时间时;特别是当你的排名与时间紧密相关时。

它适用于大多数在线评测系统、编程竞赛环境,包括ACM-ICPC(分区赛、区域赛和世界总决赛)和许多在线评测系统。

它的缺点是:

  • 增加了编译时间。
  • 使用GNU C++库的内部非标准头文件,因此无法在MSVC、XCode和许多其他编译器中编译

7
适用于 clang 的 Mac 用户:你无法预安装 stdc++.h,因为它不是标准头文件。因此,只需将以下要点粘贴到 /usr/local/include/bits 中,即可开始使用。https://gist.github.com/abe312/a078b27b03b6e29f0a19a279ec3265cd - abe312
3
如果你实际使用了很多文件,但是你的程序可能并不需要这些文件,那么这会不必要地增加编译时间和程序大小。未使用的定义和声明不会影响程序大小。 - Swordfish
@Swordfish,在编译时RAM内存大小怎么样? - abe312
3
@Swordfish 我刚刚用两个文件 a.cpp 和 b.cpp 进行了测试。 // a.cpp #include<bits/stdc++.h> int main(){ return 0; } // b.cpp int main(){ return 1; }// 编译器 gcc 在 Mac 上. 两个文件的 .out 文件大小都是 4248 字节。现在正在更新答案。 :) - abe312
2
你在GeeksForGeeks上被Ayush Govil抄袭了,他没有注明出处:https://www.geeksforgeeks.org/bitsstdc-h-c/。 Ayush从你那里复制了内容(包括标点符号错误):“从软件工程的角度来看,尽量减少include是一个好主意。如果你实际使用它包含了很多文件,而你的程序可能不需要这些文件,这样会增加编译时间和程序大小,从而不必要地增加了两者。”我讨厌抄袭。他只需要引用并提供链接,我就会很高兴。 - Gabriel Staples
显示剩余3条评论

38

那个头文件不是C++标准的一部分,因此不具备可移植性,应该避免使用。

此外,即使标准中有某个通用头文件,您也应该选择特定的头文件来代替,因为编译器必须每次编译翻译单元时都读取和解析每个包含的头文件(包括递归包含的头文件)。


15
这就是预编译头文件的作用。我有一个几乎包含整个标准库的预编译头文件。这就是我的方式。 - Neil Kirk
2
@NeilKirk:听起来对我来说不太标准。 - Robert Allan Hennigan Leahy
5
不是的,这只是大多数编译器中的一个选项,可以加快编译速度。 - Neil Kirk
10
"按定义,“大多数编译器”是非标准的——如果它是标准的,那就应该是“所有编译器”。我没有看到标准中讨论头文件如何预编译的任何地方。" - Jerry Jeremiah
如果我们避免一切不属于标准的东西,那么我们每个项目都需要重新编写所有内容。即使它们不是标准的一部分,使用其他人的库在某些时候也是一个好主意。 - Jerry Jeremiah

6

遗憾的是,这种方法在现阶段还不是可移植的C++。

所有标准名称都在命名空间std中,并且您无法知道哪些名称没有通过包括头文件而定义(换句话说,当使用#include <vector>时,实现可以直接或间接地声明名称std::string)。

尽管如此,根据语言要求,您需要告诉编译器每个标准头文件包含标准库的哪个部分。这是可移植性bug的来源,因为如果您忘记了#include <map>,但仍然使用std::map,程序可能会在特定版本的特定编译器上默默地编译而没有警告,而您只有在将其迁移到另一个编译器或版本后才可能出现错误。

在我看来,没有有效的技术借口可以解释为什么对于一般用户而言这是必需的:编译器二进制文件可以内置所有标准命名空间,这实际上甚至比使用预编译头更可以提高性能(例如使用完美哈希进行查找、删除标准头文件解析或加载/反序列化等)。

使用标准头文件可简化编译器或标准库构建者的工作,仅此而已。这并不是为了帮助用户。

然而,这就是语言的定义方式,您需要知道哪个头文件定义了哪些名称,因此要计划额外的神经元来记住这一点(或尝试找到一个自动添加您使用的标准头文件并删除不需要的头文件的IDE...这是一个合理的替代方案)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接