我应该在C ++程序中包含<xxxx.h>还是<cxxxx>吗?
- 我应该在C ++程序
stdio.h
或cstdio
中包含什么? 为什么? - 为什么两个提供相同功能的头文件?
- 标准对此有何说法?
- 我应该如何包括其他此类标头?是否有应遵循的基本规则?
请考虑以下程序:
范例1:
#include<stdio.h>
int main()
{
printf("Hello World");
return 0;
}
范例2:
#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在内的全局名称空间和可能的std名称空间中都将导入符号名称。
让我们将此规则应用于示例代码并衡量其优缺点:
范例1:这会将来自stdio.h的所有符号带入全局名称空间。 优点是,由于符号是在全局名称空间中导入的,因此可以无限制地使用它们。 不利的一面是,您最终用许多您可能永远不会使用的符号名称来污染全局名称空间。 这可能导致符号名称冲突。 在C ++中,始终将全局名称空间视为雷区,并尽可能避免使用它。
范例2:这是一个非常糟糕的做法,因为无法保证实现会将符号放在全局名称空间中,而标准完全不需要这样做。 我们只是依靠一种特定的编译器实现的行为。 我们不能也不应该假设所有编译器都会这样做。 因此严格来说,该程序不是标准批准的,并且此用法不能在所有实现中移植。
那么正确的用法是什么?
正确的用法是使用<math.h>
并完全限定符号名称,否则将它们包含在<math.h>
声明中。 这保证了我们使用的所有符号都存在于<cmath>
命名空间中,并且我们不会污染全局命名空间。 正确用法示例:
范例3:
#include<cstdio>
using std::printf;
int main()
{
printf("Hello World");
return 0;
}
请注意,指令<math.h>
(尤其是在标头中)不是一个好的选择,您应始终使用<math.h>
声明。
请注意,我们将<math.h>
与<cmath>
进行比较,这里仅是一个示例用例,实际上,它适用于所有大多数cxxxx
和xxxx.h
标头,除了少数几个如<math.h>
和<cmath>
。
由于这篇文章有点老,我想分享以下内容:
看代码:
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标头
<X.h>
、<complex>
和<tgmath.h>
没有C ++标头,C标头本身也没有 C ++的一部分。C ++标头
<X.h>
(D.4.1)和<complex>
(D.4.4)以及它们相应的C标头<tgmath.h>
和<complex>
包含C标准库中的任何内容,而是 仅包含C ++标准库中的其他标头。
D.5 C标准库头文件[depr.c.headers] 1.为了与C标准库兼容,C ++标准库提供了表141中所示的C标头。
C ++ 11和C ++ 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标头,因为我们没有 相应的标题
<X.h>
、<complex>
或<tgmath.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>
标头
<X.h>
行为就像它只是包含标题<complex>
。 标头<tgmath.h>
的行为就好像它仅包含标头<complex>
和<cmath>
。
Bjarne Stroustrup建议最大程度地实现以下两者之间的互操作性 C和C ++语言,通过最大程度地减少不兼容性 可能。 其他人则相反,因为它使事情复杂化。
因此,似乎<X.h>
不会去任何地方。 最终,您可以同时使用两者。 就我个人而言,我将决定使用哪种代码归结为使您的代码向后兼容C代码。