为什么我不应该#include ?
我用我的代码发布了一个问题,其唯一的 #include
指令如下:
#include <bits/stdc++.h>
我的老师告诉我这样做,但在评论部分我被告知我不应该这样做。
为什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
包含
似乎在 Stack Overflow 上越来越常见,也许是本学年国家课程中新添加的内容。我想这样的优点是模糊的:
#include
行。不幸的是,这是一个懒惰的黑客,直接命名 GCC 内部标头而不是单独的标准标头,例如
、< ;iostream>
和
。它破坏了便携性并养成了可怕的习惯。缺点包括:
不要这样做!
更多信息:
原因示例:
Including
<bits/stdc++.h>
appears to be an increasingly common thing to see on Stack Overflow, perhaps something newly added to a national curriculum in the current academic year.I imagine the advantages are vaguely given thus:
#include
line.Unfortunately, this is a lazy hack, naming a GCC internal header directly instead of individual standard headers like
<string>
,<iostream>
and<vector>
. It ruins portability and fosters terrible habits.The disadvantages include:
Don't do it!
More information:
Example of why Quora is bad:
为什么?因为它的使用方式就好像它应该是 C++ 标准头一样,但没有标准提及它。所以你的代码在构造上是不可移植的。您在 cppreference 上找不到任何相关文档。所以它也可能不存在。这是某人的想象:)
我发现——令我恐惧和难以置信——有一个著名的教程网站,其中每个 C++ 示例似乎都包含此标头。世界疯了。这就是证据。
致任何编写此类“教程”的人
请停止使用此标题。忘记它吧。不要传播这种疯狂。如果您不愿意理解为什么这样做是错误,请相信我的话。我根本不喜欢被视为任何事情上的权威人物,而且我可能有一半的时间都充满这种感觉,但我只会在这一种情况下破例。我声称我知道我在这里在说什么。请相信我的话。我恳求你。
PS我完全可以想象这种邪恶想法可能发生的可恶的“教学标准”,以及导致它的情况。仅仅因为似乎有实际需要,并不意味着它是可以接受的——即使现在回想起来也是如此。
PPS 不,没有实际需要。 C++ 标准头文件并不多,而且有详细的文档记录。如果你教书,你就会通过添加这样的“魔法”来伤害你的学生。培养具有神奇心态的程序员是我们最不想要的。如果您需要向学生提供 C++ 的子集以使他们的生活更轻松,只需制作一份讲义,其中包含适用于您教授的课程的简短标题列表,以及您希望学生使用的库结构的简明文档。
Why? Because it is used as if it were supposed to be a C++ standard header, but no standard mentions it. So your code is non-portable by construction. You won't find any documentation for it on cppreference. So it might as well not exist. It's a figment of someone's imagination :)
I have discovered - to my horror and disbelief - that there is a well-known tutorial site where every C++ example seems to include this header. The world is mad. That's the proof.
To anyone writing such "tutorials"
Please stop using this header. Forget about it. Don't propagate this insanity. If you're unwilling to understand why doing this is Wrong, take my word for it. I'm not OK being treated as a figure of authority on anything at all, and I'm probably full of it half the time, but I'll make an exception in this one case only. I claim that I know what I'm talking about here. Take me on my word. I implore you.
P.S. I can well imagine the abominable "teaching standard" where this wicked idea might have taken place, and the circumstances that led to it. Just because there seemed to be a practical need for it doesn't make it acceptable - not even in retrospect.
P.P.S. No, there was no practical need for it. There aren't that many C++ standard headers, and they are well documented. If you teach, you're doing your students a disservice by adding such "magic". Producing programmers with a magical mindset is the last thing we want. If you need to offer students a subset of C++ to make their life easier, just produce a handout with the short list of headers applicable to the course you teach, and with concise documentation for the library constructs you expect the students to use.
有一个名为 Programming Puzzles & 的 Stack Exchange 网站。代码高尔夫。该网站上的编程难题符合难题的定义:
它们的设计目的是为了娱乐,而不是像一个正在工作的程序员可能会被日常工作中遇到的现实问题所娱乐的那样。
Code Golf 是“一种休闲计算机编程竞赛,参与者力求获得尽可能短的资源实现某种算法的代码。”在 PP&CG 网站的答案中,您会看到人们在答案中指定了字节数。当他们找到一种方法来减少一些字节时,他们会删除原始数字并记录新数字。
正如您所料,代码高尔夫会奖励极端的编程语言滥用。单字母变量名。没有空格。创造性地使用库函数。未记录的功能。非标准编程实践。令人震惊的黑客行为。
如果程序员在工作中提交了包含高尔夫风格代码的拉取请求,它将被拒绝。他们的同事会嘲笑他们。他们的经理会顺便到他们的办公桌旁聊天。即便如此,程序员们还是通过向 PP&CG 提交答案来取乐。
这与 stdc++.h 有什么关系?正如其他人指出的那样,使用它是懒惰的。它是不可移植的,因此您不知道它是否适用于您的编译器或下一个版本的编译器。它会养成坏习惯。它是非标准的,因此您的程序的行为可能与您的预期不同。它可能会增加编译时间和可执行文件大小。
这些都是有效且正确的反对意见。那么为什么有人会使用这个怪物呢?
事实证明,有些人喜欢没有代码高尔夫的编程难题。他们聚集在一起,在 ACM-ICPC、Google Code Jam 和 Facebook Hacker Cup 等活动中,或者在 Topcoder 和 Codeforces 等网站上进行竞争。他们的排名取决于程序的正确性、执行速度以及提交解决方案的速度。为了最大限度地提高执行速度,许多参与者使用 C++。为了最大限度地提高编码速度,其中一些使用
stdc++.h
。这是个好主意吗?让我们检查一下缺点。可移植性?这并不重要,因为这些编码活动使用参赛者事先知道的特定编译器版本。符合标准吗?与使用寿命小于一小时的代码块无关。编译时间和可执行文件大小?这些不是比赛评分标准的一部分。
所以我们留下了坏习惯。这是一个有效的反对意见。通过使用此头文件,参赛者可以避免了解哪个标准头文件定义了他们在程序中使用的功能。当他们编写实际代码(而不是使用
stdc++.h
)时,他们将不得不花时间查找这些信息,这意味着他们的工作效率会降低。这就是使用stdc++.h
进行练习的缺点。这就提出了一个问题:如果竞争性编程鼓励了使用
stdc++.h
和违反其他编码标准等坏习惯,那么为什么值得参加竞争性编程呢?一个答案是,人们这样做的原因与他们在 PP&CG 上发布程序的原因相同:一些程序员发现在类似游戏的环境中使用他们的编码技能很有趣。因此,是否使用 stdc++.h 的问题归结为编程竞赛中编码速度的好处是否超过了使用它可能养成的坏习惯。
这个问题问:“为什么我不应该#include
?”我意识到提出这个问题并回答这个问题是为了表明一个观点,并且接受的答案旨在成为该问题的唯一正确答案。但问题不是“为什么我不应该在生产代码中#include
?”因此,我认为考虑答案可能不同的其他场景是合理的。There's a Stack Exchange site called Programming Puzzles & Code Golf. The programming puzzles on that site fit this definition of puzzle:
They are designed to amuse, and not in the way that a working programmer might be amused by a real-world problem encountered in their daily work.
Code Golf is "a type of recreational computer programming competition in which participants strive to achieve the shortest possible source code that implements a certain algorithm." In the answers on the PP&CG site, you'll see people specify the number of bytes in their answers. When they find a way to shave off a few bytes, they'll strike out the original number and record the new one.
As you might expect, code golfing rewards extreme programming language abuse. One-letter variable names. No whitespace. Creative use of library functions. Undocumented features. Nonstandard programming practices. Appalling hacks.
If a programmer submitted a pull request at work containing golf-style code, it would be rejected. Their co-workers would laugh at them. Their manager would drop by their desk for a chat. Even so, programmers amuse themselves by submitting answers to PP&CG.
What does this have to do with
stdc++.h
? As others have pointed out, using it is lazy. It's non-portable, so you don't know if it will work on your compiler or the next version of your compiler. It fosters bad habits. It's non-standard, so your program's behavior may differ from what you expect. It may increase compile time and executable size.These are all valid and correct objections. So why would anyone use this monstrosity?
It turns out that some people like programming puzzles without the code golf. They get together and compete at events like ACM-ICPC, Google Code Jam, and Facebook Hacker Cup, or on sites like Topcoder and Codeforces. Their rank is based on program correctness, execution speed, and how fast they submit a solution. To maximize execution speed, many participants use C++. To maximize coding speed, some of them use
stdc++.h
.Is this is a good idea? Let's check the list of disadvantages. Portability? It doesn't matter since these coding events use a specific compiler version that contestants know in advance. Standards compliance? Not relevant for a block of code whose useful life is less than one hour. Compile time and executable size? These aren't part of the contest's scoring rubric.
So we're left with bad habits. This is a valid objection. By using this header file, contestants are avoiding the chance to learn which standard header file defines the functionality they're using in their program. When they're writing real-world code (and not using
stdc++.h
) they'll have to spend time looking up this information, which means they'll be less productive. That's the downside of practicing withstdc++.h
.This raises the question of why it's worth taking part in competitive programming at all if it encourages bad habits like using
stdc++.h
and violating other coding standards. One answer is that people do it for the same reason they post programs on PP&CG: some programmers find it enjoyable to use their coding skills in a game-like context.So the question of whether to use
stdc++.h
comes down to whether the coding speed benefits in a programming contest outweigh the bad habits that one might develop by using it.This question asks: "Why should I not #include
<bits/stdc++.h>
?" I realize that it was asked and answered to make a point, and the accepted answer is intended to be the One True Answer to this question. But the question isn't "Why should I not #include<bits/stdc++.h>
in production code?" Therefore, I think it's reasonable to consider other scenarios where the answer may be different.来自 N4606,工作草案,编程语言 C++ 标准:
没有 头文件。那里。这并不奇怪,因为标头是实现细节,通常带有警告:
<位/stdc++.h>还带有警告:
From N4606, Working Draft, Standard for Programming Language C++ :
There's no <bits/stdc++.h> there. This is not surprising, since <bits/...> headers are implementation detail, and usually carry a warning:
<bits/stdc++.h> also carries a warning:
我至少喜欢通过查看这个头文件来看到可以包含的所有头文件的列表,以及它们属于哪个版本的 C++。在这方面它确实很有用。
包含
真的有多糟糕吗?我想查看一些真实数据 - 一些用于比较编译时间和二进制可执行文件大小的数字。因此,这是一个快速的“hello world”比较测试。
注意:要了解
头文件的位置以及其中的内容,请直接跳至底部标题为“
在哪里以及什么?”的部分。摘要:
包含
“包含所有标头”标头很容易,但编译速度相对较慢。包含
头文件与 GCC/g++ 编译器一起工作正常(大概是 LLVM Clang 编译器也是如此,因为它们的目标是与 GCC 兼容),并且我的测试
这是一个示例 C++ 程序:
include_bits_stdc++.cpp:
以下是一些构建和运行命令:
WithOUT
#include
at 如果我按原样运行上面的“compile”命令,我会看到以下 10 个编译时间:
平均编译时间:
(0.362 + 0.372 + 0.502 + 0.383 + 0.367 + 0.283 + 0.294 + 0.281 + 0.292 + 0.276)/10
=0.3412
秒。size bin/a
显示:WITH
#include
位于前10 个编译时间:
平均编译时间: <代码>(1.398 + 1.006 + 0.952 + 1.331 + 1.549 + 1.454 + 1.417 + 1.541 + 1.546 + 1.558)/10 =
1.3752
秒。size bin/a
显示:结论
因此,包含标头可以在 gcc/g++ 编译器中正常工作,并且使二进制可执行文件大小没有差异,但需要 1.3752 秒/ 0.3412 秒 = 编译时间延长 4 倍!
位于何处、是什么?摘要
头文件作为 gcc/g++ 编译器的一部分包含在内。您可以使用以下命令在 Linux(例如:Ubuntu)系统上找到它:
上面的命令几乎是即时的。但是,如果没有找到任何内容,您可以像这样搜索整个文件系统,这将花费更长的时间:
如果在 Linux Ubuntu 上,
bits/stdc++.h>
将位于您的本地系统上:/usr/include/x86_64-linux-gnu/c++/8/bits/stdc++.h
/usr/include/x86_64-linux-gnu/c++ /11/bits/stdc++.h
这里可以直接在线查看gcc源代码中的文件:gcc/ libstdc++-v3/include/precompiled/stdc++.h
我至少喜欢看到可以包含的所有标头的列表,以及它们的 C++ 版本属于,通过查看该头文件。在这方面,它确实很有用。
详细信息
如果您在具有出色索引器的 IDE 中打开上面的代码,例如 Eclipse(它具有我发现的最好的索引器;它的索引要好得多< /em> 而非 MS VSCode),并且在
#include
行上Ctrl + 单击,则会跳转直接到您系统上的那个头文件!在 Linux Ubuntu 上,它直接跳转到此路径并打开此文件:/usr/include/x86_64-linux-gnu/c++/8/bits/stdc++.h
。您可以直接在 gcc 源代码中查看该文件的最新版本,此处: gcc/libstdc++-v3/include/precompiled/stdc++.h。 它只是一个头文件,包含所有其他头文件!这非常有用且富有洞察力,只需在一个位置查看所有头文件即可了解它们的内容是什么以及它们包括什么!同样,在 Eclipse 中,您可以轻松地 Ctrl + Click 每个包含的头文件直接跳转到其源代码实现。
以下是 gcc 编译器附带的完整、最新的
头文件。如果您想将其包含在您自己的个人项目中或与其他编译器一起使用,您始终可以复制并粘贴此内容并自行创建此文件。gcc/libstdc++-v3/include/precompiled/stdc++.h:
另请参阅
#include
size
中text
、data
、bss
和dec
的含义> 输出:size
输出从“sysv”格式转换 (size --format=sysv my_executable
)转换为“berkeley”格式(size --format=berkeley my_executable
)I at least like seeing a list of all headers one can include, and which version of C++ they pertain to, by looking at this header file. It is really useful in that regard.
How bad is including
<bits/stdc++.h>
, really?I wanted to see some real data--some numbers to compare compile time and binary executable size. So, here is a quick "hello world" comparison test.
Note: to learn where is the
<bits/stdc++.h>
header file, and what is in it, jump straight down to the section at the bottom titled "Where and what is<bits/stdc++.h>
?".Summary:
Including the
<bits/stdc++.h>
"include all headers" header is easy, but comparatively slow to compile.Including the
<bits/stdc++.h>
header file works fine with the GCC/g++ compiler (and presumably the LLVM Clang compiler too, since they aim to be GCC-compatible), andMy testing
Here is a sample C++ program:
include_bits_stdc++.cpp:
Here are some build and run commands:
WithOUT
#include <bits/stdc++.h>
at the topIf I run the "compile" command above with the code as-is, here are 10 compile times I see:
Average compile time:
(0.362 + 0.372 + 0.502 + 0.383 + 0.367 + 0.283 + 0.294 + 0.281 + 0.292 + 0.276)/10
=0.3412
seconds.size bin/a
shows:WITH
#include <bits/stdc++.h>
at the top10 compile times:
Average compile time:
(1.398 + 1.006 + 0.952 + 1.331 + 1.549 + 1.454 + 1.417 + 1.541 + 1.546 + 1.558)/10
=1.3752
seconds.size bin/a
shows:Conclusions
So, including the header works fine with the gcc/g++ compiler, and makes no difference on binary executable size, but it takes 1.3752 sec / 0.3412 sec = 4x longer to compile!
Where and what is
<bits/stdc++.h>
?Summary
The
<bits/stdc++.h>
header file is included as part of the gcc/g++ compiler.You can find it on your Linux (ex: Ubuntu) system with this command:
The above command is almost instant. But, if it doesn't find anything, you can search your entire file system like this, which will take much longer:
If on Linux Ubuntu,
<bits/stdc++.h>
will be located on your local system at:/usr/include/x86_64-linux-gnu/c++/8/bits/stdc++.h
/usr/include/x86_64-linux-gnu/c++/11/bits/stdc++.h
You can view the file in the gcc source code directly online here: gcc/libstdc++-v3/include/precompiled/stdc++.h
I at least like seeing a list of all headers one can include, and which version of C++ they pertain to, by looking at that header file. It is really useful in that regard.
Details
If you open the code above in an IDE with a great indexer, such as Eclipse (which has the best indexer I've ever found; it indexes far better than MS VSCode), and Ctrl + Click on the
#include <bits/stdc++.h>
line, it will jump straight to that header file on your system! On Linux Ubuntu, it jumps straight to this path and opens this file:/usr/include/x86_64-linux-gnu/c++/8/bits/stdc++.h
.You can view the latest version of this file in the gcc source code directly, here: gcc/libstdc++-v3/include/precompiled/stdc++.h. It is simply a header file which includes all other header files! This is really useful and insightful to just look at all header files in one place to get a feel for what they are and what they include! And again, in Eclipse, you can easily Ctrl + Click on each included header file to jump right to its source code implementation.
Here is the full, latest
<bits/stdc++.h>
header file included with the gcc compiler. You can always copy and paste this content and create this file yourself if you want to include it in your own personal project or use it with another compiler.gcc/libstdc++-v3/include/precompiled/stdc++.h:
See also
How does #include <bits/stdc++.h> work in C++?
text
,data
,bss
, anddec
mean in thesize
output:size
output from "sysv" format (size --format=sysv my_executable
) to "berkeley" format (size --format=berkeley my_executable
)我们不使用:的原因
是因为效率。
我打个比方:
对于那些了解 Java 的人:
如果你问你的导师以下内容是否是一个好主意,除非他们是一个糟糕的导师,否则他们会说不:
#include... 基本上做同样的事情... 这不是不使用它的唯一原因,但是这是不使用它的主要原因之一。
对于现实生活中的类比:
想象一下,你有一个图书馆,你想从图书馆借几本书,你会把整个图书馆搬到你家旁边吗?这将是昂贵且低效的。如果你只需要 5 本书,那么只取出 5 本书......而不是整个图书馆......
看起来程序很方便,我只需要输入一个包含语句,它就可以工作,与移动整个图书馆是一样的,看我只需要搬一整个图书馆而不是一本一本地搬五本书。对你来说看起来很方便,也就是说,对于真正需要搬家的人来说?没那么多,猜猜在 C++ 中,进行移动的人将是您的计算机...计算机不会喜欢为您编写的每个源文件移动整个库:).....
The reason we do not use:
is because of effiency.
Let me make an analogy:
For those of you who know Java:
If you asked your instructor if the following was a good idea, unless they are a bad instructor they would say no:
The #include... thing does the same thing basically... That's not the only reason not to use it, but it is one of the major reasons not to use it.
For a real life analogy:
Imagine you had a library and you wanted to borrow a couple of books from the library, would you relocate the entire library next to your house?? It would be expensive and ineffiecient. If you only need 5 books, well then only take out 5... Not the whole library.....
Looks convienent to the program look I only need to type one include statement and it works, same thing with moving a whole library, look I only need to move one whole library instead of 5 books, one by one. Looks convienent to you that is, for the person who actually has to do the moving?? Not so much, and guess what in C++ the person doing the moving will be your computer... The computer will not enjoy moving the entire library for every source file you write :).....
如果您的老师是 ICPC 教练,那么他/她是对的,但如果您的老师是软件工程师可能不是。
两者都有优点和缺点:
优点:
缺点:
If your teacher is an ICPC coach then he/she is right, but if your teacher is a software engineer probably he/she is not.
There are pros and cons of both:
pros:
cons:
对我来说最大的问题是包含这个头文件将无法编译。因此,如果它存在,我必须将其删除,尝试编译并添加所需的标准头文件。
The biggest problem for me is that including this header file won’t compile. So if it’s there, I’ll have to remove it, try to compile, and add the standard header files that are needed.
我的第一个想法是,bits/stdc++.h 似乎确实是 GNU libstdc++ 的内部实现细节标头。因此,决不应该直接从 C++ 程序源中包含它。
这是基于一致的观察,即在 GNU/linux 上,名为
bits
的子目录最有可能是 GNU libc 和 GNU libstdc++ 放置其内部私有头文件的常规位置。此类标头包含实现细节,并且不能保证它们的存在在补丁编译器版本之间保持稳定。看一下
/usr/include/x86_64-linux-gnu/bits/
下的glibc头文件,几乎都禁止使用#error
直接包含指令。类似地,对于 GNU libstdc++ 标头;这些位于
/usr/include/c++/12/bits/
或/usr/include/x86_64-linux-gnu/c++/12/bits/
下(几乎)它们都在开头都有文档注释,例如:在某些
bits
子目录下进行 Grepping 似乎表明该目录确实是为实现保留的。假设 gcc 版本为 12,在 x86_64 架构上,尝试以下命令:现在,头文件
bits/stdc++.h
有点特殊,因为它用于为洞库生成预编译头。因此,它更像是一个.cpp
实现文件,而不是一个正确的.h
头文件 -.cpp
源代码不适用于包容性。关于预编译头的使用,良好的 C++ 实践是使 C++ 程序/库不依赖于是否使用预编译头来构建可执行文件/库;只需遵循“包括您使用的内容”原则即可。预编译头的使用应通过外部方式(从构建系统或命令行)指定,而不是从源文件中的#include 指令指定。
从 GNU libstdc++ 的 API 的角度来看,文件
bits/stdc++.h
并未作为其一部分公开,并且仅在创建二进制pch
,并且仅给出如何从g++
的命令行调用中使用此预编译头的说明,即它不指示直接包含任何地方的文件在源代码中;它没有作为 libstdc++ 标头集的公共 API 的一部分公开——换句话说,它是不可包含的(本质上)。My first thought would be that
bits/stdc++.h
really seems to be a internal implementation detail header of GNU libstdc++. Thus, it should never be directly included from c++ program sources.This is based on a consistent observation that on GNU/linux, subdirectories named
bits
most likely seem to be the conventional place where the GNU libc and GNU libstdc++ put their internal private headers. Such headers contain implementation details, and their existence are not guaranteed to be stable across patch compiler versions.Taking a look at the glibc headers directly located under
/usr/include/x86_64-linux-gnu/bits/
, almost all of them prohibit direct inclusion by use of#error
directives.Similarly, for the GNU libstdc++ headers; those are located under
/usr/include/c++/12/bits/
or/usr/include/x86_64-linux-gnu/c++/12/bits/
(almost) all of them have documentation comments at the beginning such as:Grepping under some
bits
subdirectories seem to indicate this directory really is reserved for the implementation. Assuming version of gcc is 12, on a x86_64 arch, try the following commands:Now, the header
bits/stdc++.h
is somewhat special, as it is used to generate a precompiled header for the hole library. As such, it is more of a.cpp
implementation file rather than a proper.h
header file --.cpp
source are not meant for inclusion.Regarding the use of precompiled headers, good C++ practice is to make C++ programs/libraries that do not depend on whether a precompiled header is used to build the executable/library; simply adhere to the "Include what you use" principle. Use of a precompiled header should be specified by external means, from the build system or the command line, but not from
#include
directives in source files.From the viewpoint of the GNU libstdc++'s API, the file
bits/stdc++.h
is not exposed as being part of it, and is only mentioned in the context of creating a binarypch
, and only gives instructions on how to use this precompiled header from the command line invocation ofg++
, namely it does not instruct to directly include the file anywhere in source code; it is not exposed as being part of the public API of libstdc++'s header set -- in other words, it is not includeable (in essence).正如 @Lightness Races in Orbit 提到的 Quora 问题,包含
bits/stdc++.h
没有任何问题在编程竞赛的背景下。可移植性、编译时间和标准化方面的缺点与此无关。如果示例代码使用该包含,那么在大学编程课程中也是如此。如果您正在编写生产代码,请不要使用它。根据您当前正在编写的代码的目的来回切换应该不是什么大问题。
As explained in the top answer to the Quora question mentioned by @Lightness Races in Orbit, there's nothing wrong with including
bits/stdc++.h
in the context of a programming competition. The disadvantages around portability, compile time, and standardization are not relevant there. The same would be true in a college programming class if the example code uses that include.If you're writing production code, then don't use it. It shouldn't be a big deal to switch back and forth depending on the purpose of the code you're currently writing.