提问人:Alok Save 提问时间:12/15/2012 更新时间:6/21/2020 访问量:14051
我应该在C++程序中包含 <xxxx.h> 还是 <cxxxx>?
Should I include <xxxx.h> or <cxxxx> in C++ programs?
问:
- 我应该在 C++ 程序中包含什么,或者?为什么?
stdio.h
cstdio
- 为什么两个头文件提供相同的功能?
- 标准对此有何规定?
- 我应该如何包含其他此类标头,是否有我应该遵循的基本规则?
答:
请考虑以下程序:
#include<stdio.h>
int main()
{
printf("Hello World");
return 0;
}
#include<cstdio>
int main()
{
printf("Hello World");
return 0;
}
两者都按预期工作。那么哪种用法更合适呢?答案是:两者都不是!惊讶?请继续阅读。
出于兼容性原因,C++ 标准库提供了所有标准 C 头文件,而 C++ 作为一种语言也提供了所有等效的头文件。按照惯例,
- 没有 C++ 标准库头文件(除了用于 C 兼容性的头文件)具有任何文件扩展名,并且
- 所有 C++ 等效的 C 标头都以 开头。
cxxxxx
C++ 标准在附录 D(规范)兼容性功能中提到了这一点:
§2 提到了重要的区分点。适用于上述示例的此规则意味着:
- 包括 cstdio 导入 std 命名空间中的符号名称,也可能导入 Global 命名空间中的符号名称。
- 包括 stdio.h 导入 Global 命名空间中的符号名称,也可能导入 std 命名空间中的符号名称。
让我们将此规则应用于示例代码,并衡量优缺点:
示例 1:这会将 stdio.h 中的所有符号引入全局命名空间中。优点是,您可以不加任何限定条件地使用符号,因为它们是在全局命名空间中导入的。缺点是,您最终会用许多可能永远不会使用的符号名称污染全局命名空间。这可能会导致符号名称冲突。在 C++ 中,始终将全局命名空间视为雷区,并尽可能避免它。
示例 2:这是一种非常糟糕的做法,因为不能保证实现会将符号放在全局命名空间中,标准根本不要求这样做。我们只是依赖于一个特定编译器实现的行为。我们不能也不应该假设所有编译器都会这样做。因此,严格来说,该程序未经标准批准,并且这种用法并非在所有实现中都是可移植的。
那么什么是正确的用法呢?
正确的用法是使用并完全限定符号名称,或者使用 using
声明将它们纳入范围。这保证了我们使用的所有符号都存在于命名空间中,并且我们不会污染全局命名空间。正确用法示例:cstdio
std
#include<cstdio>
using std::printf;
int main()
{
printf("Hello World");
return 0;
}
请注意,使用 namespace std;
的指令(尤其是在标头中)不是一个好的选择,您应该始终使用声明。using
请注意,我们考虑 vs. 这里只是一个示例用例,实际上它适用于所有 MOST 和标头,除了 <math.h
> 和 <cmath>
等少数。stdio.h
cstdio
cxxxx
xxxx.h
评论
cstdio
std::printf
stdio.h
::printf
::printf
由于这篇文章有点旧,我想分享以下内容:
查看代码:
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;
}
它们编译和执行都很好!
C++ 哪个更好?
关于 C++11 和 C++17 的规范:
C.5.1(来自 C++17 文档的部分)
对标头的修改 [diff.mods.to.headers]
- 为了与 C 标准库兼容,C++ 标准库提供了 D.5 中枚举的 C 标头,但它们的用法是 在 C++ 中已弃用。
- C 头文件 、 和 没有 C++ 头文件 ,也没有 C 头文件 本身
<stdatomic.h>
<stdnoreturn.h>
<threads.h>
C++ 的一部分。
- C++ 标头 (D.4.1) 和 (D.4.4) 及其对应的 C 标头和 不
<ccomplex>
<ctgmath>
<complex.h>
<tgmath.h>
包含 C 标准库中的任何内容,而不是 仅包含 C++ 标准库中的其他标头。
D.5 C 标准库头文件 [depr.c.headers]
- 为了与 C 标准库兼容,C++ 标准库提供了表 141 中所示的 C 头文件。
C++11 和 C++17 标准规范文档都指出了 remains 的使用是为了与 C 标准兼容,尽管它们的使用被视为已弃用。<X.h>
关于 C++ 20 标准提案
他们正在审查“不推荐使用”C++20 中的 C 库头文件。 以绿色突出显示。截至目前,C++ 和 C++ 17 的弃用被声明为“弱推荐”,并且保留“C 标准库头文件 (c.headers)”的“调整”如下所示:<X.h>
“基本的 C 库头文件是必不可少的兼容性功能,而且不会很快消失。”(摘自 C++ 20 审查文档)
D.5 C 标准
库头文件 [depr.c.headers]弱推荐:除上述内容外,还要删除 来自 C++ 标准的相应 C 头文件,就像我们没有一样 对应的 、 或 、 标头。 如上所述,但进行了以下调整: 20.5.5.2.1 C 标准库头文件 [c.headers]
<stdatomic.h>
<stdnoreturn.h>
<threads.h>
为了与 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>
标头的行为就好像它只包含标头 一样。 标头的行为就像它只包含标头和 .
<complex.h>
<complex>
<tgmath.h>
<complex>
<cmath>
Bjarne Stroustrup 建议最大限度地提高 C 和 C++ 语言,通过减少不兼容性 可能。其他人则不这么认为,因为它使事情复杂化。
所以,它似乎不会去任何地方。最终,您可以同时使用两者。就我个人而言,我会决定使用哪一个,归结为是否让你的代码与 C 代码向后兼容。<X.h>
评论
cstdio
评论