这是this的后续问题,即
在C ++中,与C不同,标准头文件允许#include其他标准头文件。
有没有办法知道哪些标题是自动包含的,因为可能很难猜出哪些标题是在哪些标题中定义的。
动机:我的作业在我的计算机上编译并正常工作,但TA告诉我它没有编译,需要几个标题(互斥和算法)来编译。我怎么能确定我将来提交的代码是防弹的。
我的编译器没有提供有关隐式声明的任何警告。
我正在使用clang++ -std=c++11
来编译我的代码。
答案 0 :(得分:5)
标准列出了每个标题提供的符号。除此之外没有任何保证,既没有明确使用的符号也没有声明所有符号。您需要为您正在使用的任何名称添加每个标头。你应该不依赖间接包含。
从积极的方面来看,标准库中没有任何标准库标题需要额外标题的情况。
答案 1 :(得分:3)
如果您想知道特定头文件提取的其他标头,最简单的方法是仅通过编译器的预处理器阶段运行包含文件,而不是完全编译它。例如,如果您想知道<iostream>
引入了什么,请创建一个仅包含:
#include <iostream>
然后预处理它。对于gcc
,-E
选项仅运行预处理程序,而不编译文件,并将预处理文件转储到标准输出。结果输出以:
# 1 "t.C"
这是我的单行源文件。
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
显然,gcc
会自动拉入此头文件,无论如何。这可以忽略不计。
# 1 "<command-line>" 2
# 1 "t.C"
# 1 "/usr/include/c++/6.2.1/iostream" 1 3
好的,现在我们终于在我的单行源文件中找到了实际的#include
语句。这就是<iostream>
所在的位置:
# 36 "/usr/include/c++/6.2.1/iostream" 3
# 37 "/usr/include/c++/6.2.1/iostream" 3
# 1 "/usr/include/c++/6.2.1/x86_64-redhat-linux/bits/c++config.h" 1 3
好的,iostream
本身#include
这个&#34; c ++ - config.h&#34;头文件,显然是内部编译器头。
如果我继续前进,我可以看到<iostream>
引入了<ios>
,<type_traits>
,以及stdio.h
等C头文件。
编写一个带有头文件的快速小脚本,在预处理阶段运行编译器,并生成一个很好的,格式化的所有头文件列表,并不是很难。
答案 2 :(得分:2)
据我所知,没有办法做你想做的事。
如果您尝试在几个示例平台上编译代码,并且它成功,那么它在任何其他平台上编译的可能性就更大,但没有简单的方法可以确定。
根据我的经验,MinGW C ++标头彼此使用的#include
更少。所以MinGW可以成为检查可移植性的实用工具。
答案 3 :(得分:1)
这个问题与Are there tools that help organizing #includes?有相当多的重叠之处,由于需要外部工具/资源,因此后者如今已被视为“题外话”。严格来说,这个问题只是关于查找间接包含的方法,但是目标肯定是相同的。
使用“正确的” include
语句的问题很难解决。问题中描述的主要是关于间接包含的:一个标头包含一个特定的符号,但是在另一台具有另一个编译器和另一个标头的计算机上,可能不包含该符号。
一些评论和其他答案建议看似务实但不切实际的方法:
明确包含要使用的事物所需的标题:这基本上是无法维护的。当您在重构过程中将一个功能从文件移动到另一个文件时,您将永远不知道可以安全地删除其中一个文件,而必须将其中一个文件添加到另一个文件中。
(而且,当您更改包含内容时,您可能会破坏包含标头的第三方代码,因为每个人都面临着相同的问题...)
所有这些都不能涵盖间接包含并不总是一个问题,但有时是有意的:当您想使用std::vector
时,您会#include <vector>
,而不是#include <bits/stl_vector.h>
,即使后者包含定义...
因此,唯一可行的解决方案是依靠支持开发人员的工具。 Are there tools that help organizing #includes?的答案中提到了一些工具,最初,我三年前在comment to the question中提到了CDT,但我认为在这里也值得一提:
这是一个提供“组织包含”功能的IDE。这些功能在https://www.eclipse.org/community/eclipse_newsletter/2013/october/article3.php的文章中进行了介绍,其中指出了困难和警告(我在上面提到了其中的一些),以及如何在CDT中解决这些问题。
尽管只是在一个非常简单的测试项目中,我已经尝试过了(很久以前)。因此,我可以说它基本上可以工作,但是考虑到任务的复杂性,它带有一个免责声明:它与魔术 close 很近,但是在某些情况下它还是会失败。
C ++不能解析和编译。这句话是正确的,因为我先前在堆栈溢出中的答案之一包含行#define not certainly
。
本文还指出了另一种工具:
我没有对此进行了尝试,但是它似乎非常活跃。 documentation pages还列出了一些困难和目标。乍一看,它似乎不像CDT那样强大和可配置(当然,它不包含在IDE中),但是有些人可能想尝试一下。