我应该在C++程序中包含<xxxx.h>还是<cxxxx>?

Alo*_*ave 50 c++ c++-faq include

  • 我应该在C++程序中包含什么,stdio.h或者cstdio?为什么?
  • 为什么两个头文件提供相同的功能?
  • 标准对此有何看法?
  • 我应该怎么做包括其他这样的标题,我应该遵循一个基本规则吗?

Alo*_*ave 60

考虑以下程序:

样本1:

#include<stdio.h>

int main()
{
    printf("Hello World");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

样本2:

#include<cstdio>

int main()
{
    printf("Hello World");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

两者都按预期工作.那么哪种用法更合适? 答案是:都没有!惊讶吗?继续阅读.

出于兼容性原因,C++标准库提供了所有标准C头,而C++作为一种语言也提供了所有等效的头.作为惯例,

  • 没有C++标准库头(除了C兼容性之外)都有任何文件扩展名,以及
  • C头的所有C++等价物都以cxxxxx.

C++标准在附录D(规范性)兼容性功能中提到了这一点:

标准引文

§2提到了重要的区分点.适用于上述示例的此规则意味着:

  • 包括cstdio在std命名空间中导入符号名称,可能还在Global名称空间中.
  • 包括stdio.h 在Global命名空间中导入符号名称,也可能在std命名空间中导入.

让我们将此规则应用于我们的示例代码并衡量利弊:

示例1: 这将stdio.h中的所有符号带入全局命名空间.优点是您可以使用符号而无需任何限定,因为它们是在全局命名空间中导入的.缺点是你最终会用许多你可能永远不会使用的符号名称来污染全局命名空间.这可能会导致符号名称冲突.在C++中,始终将全局命名空间视为雷区,并尽可能避免使用它.

示例2: 这是一种非常糟糕的做法,因为无法保证实现将符号放在全局命名空间中,标准根本不要求这样做.我们只是依赖于一个特定编译器实现的行为.我们不能也不应该假设所有编译器都会这样做.严格来说,该程序未经标准批准,并且这种用法在所有实现中都不可移植.

那么正确的用法是什么?

正确的用法是使用cstdio和完全限定符号名称,或者使用using声明将它们放在范围内.这保证了我们使用的所有符号都存在于std命名空间中,并且我们不会污染全局命名空间.正确用法示例:

样本3:

#include<cstdio>

using std::printf;

int main()
{
    printf("Hello World");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意,该指令using namespace std;(尤其是在标头中)不是一个好的选项,您应该始终使用using声明.

请注意,我们认为stdio.hcstdio在这里只是一个样本的使用情况,在实践中它适用于所有cxxxxxxxx.h头,除了少数喜欢<math.h><cmath>.

  • -1"我们没有污染全局命名空间",你刚才引用并讨论过不是这种情况.所以.有点自相矛盾.这很重要,因为它直接影响到什么是最佳实践的结论.你上面的结论是错误的.真奇怪*.你首先讨论为什么它是一个糟糕的选择(代码不能跨编译器工作的可能性,意外的命名空间污染)然后你只是声称它是"正确的用法".这是真的,因为它不是不正确的,但这是一个非常糟糕的选择. (5认同)
  • 所以...关于正确用法的结论看起来毫无根据......如果在两种情况下全局命名空间都可能,那么为什么使用`cstdio` +`std :: printf`比`stdio.h` +`:: printf`更好?污染,以便例如创建自己的`:: printf`函数是不可移植的? (3认同)

San*_*ela 5

由于这篇文章有点旧,我想分享以下内容:


看代码:

Using X.h   // Compatible with C language standard
---------------
#include <X.h>

int main() {
    // Invoke X's corresponding function
    return 0;
}

Using X    // Not compatible with C language standard
--------------
#include <X>

int main() {
    // Invoke X's corresponding function
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

他们编译和执行都好!


哪一个在C++中更好?

关于C++ 11C++ 17的规范:

C.5.1(C++ 17文档部分)对头文件的
修改[diff.mods.to.headers]

  1. 为了与C标准库兼容,C++标准库提供了D.5中枚举的C头,但在C++中不推荐使用它们.

  2. 有用于C标头中没有C++头<stdatomic.h>,<stdnoreturn.h><threads.h>,也不是C标头本身的C部分++.

  3. C++的标头<ccomplex>(D.4.1)和<ctgmath>(D.4.4),以及它们的相应的C头部<complex.h><tgmath.h>,不含有任何从C标准库的内容,而是仅包括从C++标准库其它标题.


D.5 C标准库头文件[depr.c.headers] 1.为了与C标准库兼容,C++标准库提供了表141中所示的C头.

在此输入图像描述

无论C++ 11C++ 17个标准规范注明证件使用<X.h>与C标准的兼容性遗体,但由于其使用被认为过时.


关于C++ 20标准提案

他们正在审查在C++ 20中使用C库头文件的"不引用".<X.h>以绿色突出显示.截至目前,C++ 11和C++ 17弃用被称为"弱推荐",并且用于保持" C标准库头(c.headers) " 的"调整" 如下所示:

"基本的C库头是必不可少的兼容性功能,不会很快到任何地方." (来自C++ 20评论文档)


D.5 C标准
库头文件[depr.c.headers]

弱推荐:除上述之外,还从C++标准删除相应的C头,就像我们没有相应的<stdatomic.h>,<stdnoreturn.h>或者<threads.h>,标头.如上所述,但有以下调整:20.5.5.2.1 C标准库头[c.headers]

为了与C标准库兼容,C++标准库提供了表141中所示的C头.表141-C头

 <assert.h>  <inttypes.h>   <signal.h>      <stdio.h>   <wchar.h>
 <complex.h> <iso646.h>     <stdalign.h>    <stdlib.h>  <wctype.h>
 <ctype.h>   <limits.h>     <stdarg.h>      <string.h>  
 <errno.h>   <locale.h>     <stdbool.h>     <tgmath.h>
 <fenv.h>    <math.h>       <stddef.h>      <time.h>
 <float.h>   <setjmp.h>     <stdint.h>      <uchar.h>
Run Code Online (Sandbox Code Playgroud)

标题的<complex.h> 行为就像它只包含标题一样<complex>.标题的<tgmath.h>行为就像它只包含标题<complex><cmath>.


Bjarne Stroustrup建议通过尽可能减少不兼容性最大化C和C++语言之间的互操作性.其他人则争辩说,因为它使事情复杂化.

所以,似乎<X.h>不会去任何地方.最终,你可以使用两者.就个人而言,我会决定使用哪一个让你的代码向后兼容C代码.

  • 考虑到当我开始编程时,C++ 11仍然被认为是一个新的重大事件,C++ 17几乎没有出门,人们已经在考虑使用C++ 20这个概念非常有趣. (2认同)
  • Stroustrup 的文章来自大约 15 年前,当时 C++ 的生存与 C 的流行密切相关。目前尚不清楚这在今天是否同样重要。虽然是否_设计语言_尽可能兼容是一个有趣的问题,但我不明白这方面的意见应该如何指导我们应该如何_编写 C++ 代码_。如果我的代码仅作为 C++ 代码进行过测试,那么努力使其与 C 兼容似乎是可疑的,尤其是以全局命名空间污染为代价。 (2认同)