【问题标题】:Why do some includes need the .h and others not? [duplicate]为什么有些包含需要 .h 而有些则不需要? [复制]
【发布时间】:2010-12-10 01:02:51
【问题描述】:

为什么map导入为#include <map>,而stdio导入为#include <stdio.h>

【问题讨论】:

  • stdio也可以导入为#include <cstdio>
  • @Matt:所以导入名称与文件名不同。这是怎么做到的?
  • @Casebach:通常有两个单独的文件,cstdiostdio.h,其中cstdio 包括stdio.h,其方式是将其所有符号放入命名空间std。但它的确切方式取决于实现。
  • @Casebash: 不,实际上有一个文件cstdio(或至少是编译器已知的伪文件)定义了几乎等价的标准 C++ 库函数 到标准 C 库头 stdio.h.
  • @Ben:它们可能不只是包含 C 头文件,但在流行的编译器上(我在回答之前检查了我在 MSVC 上的 cstdio 头文件)它们仍然包含它们。不过你的观点很有趣。

标签: c++ include


【解决方案1】:

所有标准 C++ 头文件最后都不想要.h。我在某处读到的概念是它们不需要是实际文件,即使我从未见过以另一种方式实现的实现 编辑: 实际上编译器内部函数应该考虑包含的头文件,但实际上并未将它们作为文件包含在内;查看@Yttrill的评论

对于stdio.h,在C++ 应用程序中不应包含<stdio.h>,而应包含<cstdio>。一般来说,你不应该包含“普通”的 C 头文件,但是它们的 C++ 化头文件最终没有 .h,在前面有一个 c 并且 把所有符号在std 命名空间中定义它们。所以,<math.h> 变为 <cmath><stdlib.h> 变为 <cstdlib>,以此类推。

一般来说,您应该使用 C++ 版本的 C 标头,以避免污染全局命名空间(假设您不是将using namespace std; 放在任何地方的人之一)并受益于一些 C++ 改进标准 C 头文件(例如,向某些数学函数添加重载)。


一般来说,整个事情的实现只是通过在编译器查找头文件的目录中没有扩展名的文件来完成。例如,在我的 g++ 4.4 安装中,您有:
matteo@teoubuntu:/usr/include/c++/4.4$ ls
algorithm           cstdarg              functional        sstream
array               cstdatomic           initializer_list  stack
backward            cstdbool             iomanip           stdatomic.h
bits                cstddef              ios               stdexcept
bitset              cstdint              iosfwd            streambuf
c++0x_warning.h     cstdio               iostream          string
cassert             cstdlib              istream           system_error
ccomplex            cstring              iterator          tgmath.h
cctype              ctgmath              limits            thread
cerrno              ctime                list              tr1
cfenv               cwchar               locale            tr1_impl
cfloat              cwctype              map               tuple
chrono              cxxabi-forced.h      memory            typeinfo
cinttypes           cxxabi.h             mutex             type_traits
ciso646             debug                new               unordered_map
climits             deque                numeric           unordered_set
clocale             exception            ostream           utility
cmath               exception_defines.h  parallel          valarray
complex             exception_ptr.h      queue             vector
complex.h           ext                  random            x86_64-linux-gnu
condition_variable  fenv.h               ratio
csetjmp             forward_list         regex
csignal             fstream              set

C++ 化的 C 头文件理论上可能只是一个

namespace std
{
#include <original_C_header.h>
};

但一般来说,它们在处理特定于实现的问题(尤其是关于宏)和添加与 C++ 相关的功能(例如,参见 &lt;cmath&gt; 中添加重载的上一个示例)时更加复杂。


顺便说一句,C++ 标准(§D.5)并没有说 &lt;c***&gt; 标头应该表现得好像它们在 namespace std 指令中包含了 &lt;***.h&gt; 标头,但相反:

为了与标准 C 库兼容,C++ 标准库提供了 18 个 C 头文件 [...] 每个名称格式为 name.h 的 C 标头的行为就好像每个由相应 cname 标头放置在标准库命名空间中的名称也放置在命名空间 std 的命名空间范围内,并且后跟显式 using-声明(7.3.3)

请注意,此类标头已被弃用(§C.2.1),因此这是您不应使用它们的主要原因:

C.2.1 对标头的修改 为了与标准 C 库兼容,C++ 标准库提供了 18 个 C 头文件 (D.5), 但它们在 C++ 中已被弃用。

【讨论】:

  • 由于 Matteo 实际上并没有提供任何理由来使用 C 标准头文件的 C++ 版本,我将给出一个:C++ 头文件通常提供 C 标准库函数的重载版本,它针对参数的实际数据类型进行了优化。 C 也提供了这些多个版本,但它们都有不同的名称(例如 abs vs fabs vs fabs vs fabsl)。如果您使用模板,则与 #include&lt;cmath&gt; 不同,否则或对于其他标题则没有太大区别。
  • @Ben Voigt:有趣的是,我在上一个版本中独立添加了它(在快速浏览了cmath 文件之后):)
  • 命名空间污染实际上并不是使用 C++ 版本头文件的理由,因为没有人会使用与 C 标准库冲突的命名
  • @Matteo:当然,您确实看到了不使用头文件的实现,包括 gnu 和 MS 编译器在内的所有生产编译器都支持将 memcpy() 等函数实现为内在函数:头文件可能作为文件存在并包含回退定义,但这并不意味着编译器实际上正在使用它们。
  • 人们可能应该知道,deprecation 是如此迂腐和不切实际,以至于 C++ 标准委员会甚至考虑不弃用它,尽管没有对 C++20 做出任何结论:@987654321 @.
【解决方案2】:

它只是磁盘上实际文件的名称。在您的标准包含目录中(可能)没有名为 map.hstdio 的文件。

C++ 标准库从以前使用.h 的风格转变为在文件名末尾不使用.h。这可能可能与使语法看起来更像模板有关:

#include<vector>

vector<int> v;

(抢先评论:是的,我知道上面需要std::来构建,但这只是一个说明。)

【讨论】:

  • 我不想对竞争性答案投反对票,但这实际上是不准确的——不能保证文件mapstdio.h 存在于磁盘上。
  • 是的,没有保证。大多数编译器将标准库头文件作为文件存储在磁盘上,当然流行的常用的也可以。
  • 当然——这是显而易见的实现选择。我没有投反对票,只是想观察到“它只是磁盘上实际文件的名称”就标准而言并不完全准确。
【解决方案3】:

这正是 C++ 标准定义的方式——碰巧,mapstdio.h 甚至不必是真实文件。

附带说明,stdio.h 是最初从 C 标准库导入 C++ 的标头——C++ 版本是cstdio。实际上,这通常意味着当您包含 cstdio 时,您会从 stdio.h 获取内容,但它位于命名空间 std 中。

澄清一下:您在 C++ 中包含的 stdio.h 是最初 C 头文件的 C++ 版本。但是编写包含的 C++ 方式是cstdio

【讨论】:

  • 不,C++ 程序中的 #include&lt;stdio.h&gt; 不会为您提供 C 标准库中的版本(或者无论如何它不应该),请参阅 stackoverflow.com/questions/4405887/…
  • @Ben:确实,我的措辞是错误的——我的意思是说这是编写 C++ 包含的 C 风格的方式,它不会将东西放入命名空间 std。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多