【问题标题】:How does #include <bits/stdc++.h> work in C++? [duplicate]#include <bits/stdc++.h> 如何在 C++ 中工作? [复制]
【发布时间】:2014-10-08 06:42:44
【问题描述】:

我从codeforces 博客中读到,如果我们在C++ 程序中添加#include &lt;bits/stdc++.h&gt;,则无需包含任何其他头文件。 #include &lt;bits/stdc++.h&gt; 是如何工作的,是否可以使用它而不是包含单个头文件?

【问题讨论】:

  • 这很可能是出于教育目的。我假设 bits/stdc++.h 包含所有 C++ 头文件。
  • 从头文件本身:这是一个预编译头文件的实现文件。
  • @MarcoA。因为 1980 年的计算机内存较少。
  • @NeilKirk:我使用了你提到的那个工具,点击第一个链接,到达这个页面,然后看到你的评论,然后陷入了循环。
  • BS 曾经努力为新用户和快速玩具构建标准化厨房水槽头。它以某种方式死了(大型实际项目的坏做法?我还记得他们希望发布和调试具有相同的 ABI,但这是不可行的)。我找不到参考文件。我认为这样的标题有一个合法的利基市场。虽然当我们得到模块时,这一切都应该神奇地消失了。

标签: c++ gcc c++11 g++


【解决方案1】:

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

此外,即使标准中有一些包罗万象的标头,您也希望避免使用它来代替特定标头,因为编译器必须实际读取并解析每个包含的标头(包括递归包含的标头)编译该翻译单元的单次。

【讨论】:

  • 这就是预编译头文件的用途。我有一个几乎包含整个标准库的东西。就是这样滚动。
  • @NeilKirk:对我来说听起来不标准。
  • 不,不是。这是大多数编译器的一个选项来加速它。
  • 根据定义,“大多数编译器”是非标准的——如果它是标准的,那么它将是“所有编译器”,我在标准中看不到任何关于如何预编译头文件的地方......
  • 如果我们避免不属于标准的所有内容,那么我们将为每个项目重写所有内容。在某些时候使用其他人的库是一个好主意,即使它们不是标准的一部分。
【解决方案2】:

它基本上是一个头文件,还包括每个标准库和 STL 包含文件。我能看到的唯一目的是测试和教育。

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

使用它会包含很多不必要的东西并增加编译时间。

编辑: 正如 Neil 所说,它是预编译头文件的实现。如果您正确设置它以进行预编译,实际上它可以根据您的项目加快编译时间。 (https://gcc.gnu.org/onlinedocs/gcc/Precompiled-Headers.html)

不过,我建议您花时间了解每个 sl/stl 标头,并将它们分别包含在内,并且不要使用“超级标头”,除非用于预编译目的。

【讨论】:

  • 用于预编译头文件,减少编译时间! (设置正确时)
  • 我认为学习 C++ 完全不知道你正在使用的东西是在哪里定义的不是很好。你在什么时候停下来弄清楚?
  • @OllieFord 从不,理想情况下。这是21世纪。编译器应该弄清楚我需要标准库的哪些部分,以节省我编写重要内容的时间。但当然人们应该了解标题,因为它是语言的一部分。
  • 否,但取决于学生年龄和课程等...
  • 包含它的一个小缺点是它会导致命名空间中有很多名称。在极少数情况下,这可能会导致一些难以理解的错误(持续几秒钟)。例如,如果您的变量之一被命名为count。但目前我想不出一个具体的令人困惑的错误示例......
【解决方案3】:

#include &lt;bits/stdc++.h&gt; 是预编译头文件的实现文件。

从软件工程的角度来看,尽量减少包含是一个好主意。如果您使用 它实际上包含很多文件,您的程序可能不需要这些文件,从而不必要地增加编译时间和程序大小。 [编辑: 正如@Swordfish 在 cmets 中指出的那样,输出程序大小不受影响。但是,最好只包含您实际需要的库,除非是一些竞争性的竞争]

但是在比赛中,当你想减少浪费在做家务上的时间时,使用这个文件是个好主意;尤其是当您的排名对时间敏感时。

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

它的缺点是:

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

【讨论】:

  • 对于使用 clang 的 mac 用户:您不会预先安装 stdc++.h,因为它不是标准头文件。因此,只需将以下要点粘贴到 /usr/local/include/bits 中即可。 gist.github.com/abe312/a078b27b03b6e29f0a19a279ec3265cd
  • 我刚从codechef.com 来到这里,目的是在各种竞赛问题的解决方案中包含这个标题。这个解释很有道理。 +1
  • @abe312 "如果你使用它实际上包含很多你的程序可能不需要的文件,从而不必要地增加编译时间和程序大小。"如果不使用,包括未使用的定义和声明不会影响程序大小。
  • @Swordfish 编译时 RAM 内存大小如何?
  • @Swordfish 我刚刚用 2 个文件 a.cpp 和 b.cpp 对其进行了测试 // a.cpp #include int main(){ return 0; } // b.cpp int main(){ return 1; } // mac 上的编译器 gcc。 .out 大小 => 4248 字节。现在更新答案。 :)
【解决方案4】:

不幸的是,这种方法不是可移植的 C++(到目前为止)。

所有标准名称都在命名空间 std 中,而且您不知道哪些名称是 NOT 由 include 和 header 定义的(换句话说,实现声明名称 std::string 是完全合法的直接或间接使用#include &lt;vector&gt;)。

尽管如此,但是语言要求您知道并告诉编译器哪个标准头文件包含标准库的哪个部分。这是可移植性错误的来源,因为如果您忘记了例如#include &lt;map&gt; 但使用std::map,则程序可能会以静默方式编译,并且在特定编译器的特定版本上没有警告,并且您可能会在稍后移植时遇到错误到另一个编译器或版本。

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

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

但是这是定义语言的方式,您需要知道哪个标头定义了哪些名称,因此计划在无意义的配置中燃烧一些额外的神经元以记住这一点(或尝试找到自动添加标准标头的 IDE您使用并删除您不使用的那些...一个合理的选择)。

【讨论】:

    猜你喜欢
    • 2014-10-09
    • 2022-01-11
    相关资源
    最近更新 更多