在C ++中使用C标头时,我们应该使用std ::或全局名称空间中的函数吗?


113

C在某种程度上,也不完全是C ++的子集。因此,我们可以通过改变名称一点点(使用最多的C函数的C /头++ stdio.hcstdiostdlib.hcstdlib)。

我的问题实际上是一种语义。在C ++代码(使用最新版本的GCC编译器)中,我可以调用printf("Hello world!");std::printf("Hello world!");,它的工作原理完全相同。在我正在使用的参考资料中,它也显示为std::printf("Hello world!");

我的问题是,是否首选std::printf();在C ++中使用?有区别吗?


17
如果有一天他们要求将C库符号转储到全局名称空间中是非法的,那么我更喜欢使用std::限定版本。(此外,我还希望他们将其定为非法)。
Galik 2015年

3
@加里克:同意。使用C ++编译器可以解决许多关于C问题的愚蠢问题。
对于这个网站来说太老实了

7
没有“一点点怀孕”。C要么是子集,要么不是。事实是,不是。这就是必须修改C标头才能在C ++中工作的原因。
对于这个网站来说太老实了

2
当谈论一组不可数的许多元素时,“几乎全部”是一个非常无用的度量。通过相同的论点,您可能将C和Java联系起来。
Daniel Jour

9
@sasauke不,它不是子集。C和C ++肯定共享一个子集,但是C本身不是 C ++的子集。
顺磁牛角包

Answers:


106

从C ++ 11标准(重点是我的):

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

  1. 为了与C标准库兼容...
  2. 每个C头(每个头具有形式为name.h的名称)的行为就像是将由相应cname头放置在标准库名称空间中的每个名称都放在全局名称空间范围内。这是未指定的这些名字是否首次宣布或命名空间范围内定义(3.3.6)命名空间性病,然后通过使用明确的-声明(7.3.3)注入到全局命名空间范围。
  3. 示例:标头<cstdlib> 肯定会在namespace中 std提供其声明和定义。它还可以在全局名称空间中提供这些名称。该标头<stdlib.h> 肯定会在全局名称空间中提供与C标准中相同的声明和定义。它还可以在名称空间中提供这些名称std

不建议使用«name.h»标头,已将其标识为可从将来的修订版中删除的标头。

因此,我建议包括«cname»标头,并使用std命名空间中的声明和定义。

如果由于某些原因(不推荐使用,请参见上文)而必须使用«name.h»标头,我建议使用全局名称空间中的声明和定义。

换句话说:喜欢

#include <cstdio>

int main() {
    std::printf("Hello world\n");
}

过度

#include <stdio.h>

int main() {
    printf("Hello world\n");
}

1
N3242不是任何C ++标准。N3337与C ++ 11差异最小的草案。
MM

3
另请参阅乔纳森·韦克利(Jonathan Wakely)的《为什么<cstdlib>》比您从Red hat博客中想到的要复杂的多。他从C ++标准库实现者的角度详细介绍了许多问题。他还提供了可以追溯到C ++ 98的历史。
jww

@sergej-您是否会知道该主题的C ++ 03处理?还是碰碰运气会发生什么?
jww

5
<name.h>可能已被弃用,没有机会很快将其删除。实际上,恰恰相反。有建议删除不推荐使用的标签,请参阅open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5“最后,似乎很清楚,C头实际上将永远保留,作为与C和POSIX至关重要的兼容性层。值得不提倡使用这些头,[..]”
Sjoerd

81

<cmeow>总是提供::std::purr或可能提供或不提供::purr

<meow.h>总是提供::purr或可能提供或不提供::std::purr

请使用您所包含的标题保证提供的表格。


7
STL伪装得不好?
nwp

@nwp不。(15个字符)
TC

@TC不幸的是,当我尝试使用编译器时,既未提供也<cmeow><meow.h>提供预处理器错误。仅和/或提供和/或。:P::std::purr::purr<cstdio><stdio.h>::std::printf::printf
LF

4
@LF您可能需要strcat产生::purr
伦丁

8

不,这两种方法都很好。

最初的目的就是让这个<___.h>标题会是这把一切都放在全局命名空间中的C版本和<c___>标题将是C ++ -指明分数的版本,这一切都发生在std命名空间。

但是实际上,C ++版本还将所有内容都放入了全局名称空间。并没有明确的共识认为使用这些std::版本是“正确的事情”。

因此,基本上,使用您喜欢的任何一种。最常见的可能是在全局名称空间(printf而不是std::printf)中使用C标准库函数,但是没有太多理由认为一个“更好”。


2
“并且没有明确的共识认为使用std ::版本是“正确的事情”。” 嗯,是的,绝对可以达成共识。
Miles Rout 2015年

4
如何客观地确定是否达成共识?
杰里米·弗里斯纳

9
@JeremyFriesner,您可以在SO上发布有关它的信息,看看是否有不同意见。:)
杰夫

1
@JeremyFriesner:标准不保证C ++头版本将标识符放在全局名称空间中。该标准还弃用了C标头版本。在我看来,这非常共识。;-)
DevSolar

2
@DevSolar然后在字典中查找单词“ consensus”。它与标准所说的无关,而与C ++程序员所说的无关 -特别是他们所做的事情。有一个原因是,实际上每个标准库实现都提供C头,并且让C ++头也将所有内容都放在全局名称空间中。:)
杰夫2015年

3

唯一的区别是,std::printf()通过添加std::范围解析,您可以防止将来有人使用相同名称编写函数,这会导致名称空间冲突。两种用法都会导致完全相同的OS API调用(您可以在Linux下通过运行进行检查strace your_program)。

我发现几乎没有人会像这样命名一个函数,因为它printf()是目前最常用的函数之一。同样,在C ++中,iostreams优先于对cstdio诸如printf之类的函数的调用。


1
相反,我发现这很有可能:printf由于C ++缺少强类型,因此在C ++中被严重破坏,用更好的版本替换它是很自然的。
Konrad Rudolph 2015年

1
@KonradRudolph如果您愿意,可以用这种方式找到它,但是您会错的。它并不意味着具有强类型,并且许多问题不能通过所需的强类型轻松解决。这就是为什么许多可比的C ++解决方案比printf慢得多的原因。如果您想用“更好”的版本代替它,那么您正在打破语言和程序员之间的契约,并且一开始就处于犯罪状态。
爱丽丝

1
@Alice Uhm,我没有违反任何约定:std::printf与有所不同mynamespace::printf,C ++明确允许我定义自己的函数,其名称遮盖了其中的函数std。这根本无法争论。至于您的声明printf由于键入松散而有效,那当然也是错误的。printf甚至不是特别有效,强类型有许多更有效的实现。
Konrad Rudolph

@KonradRudolph绝对不正确;您违反了标准编写的约定,即没有任何量词的printf明显适用于C构造。您使用名称空间作为全局名称空间的别名不是一个好主意。那根本是不值得商bat的
爱丽丝

5
@Alice能否请您引用此标准?我不知道有任何这样的说法。
康拉德·鲁道夫2015年

3

从C ++ 11标准:

每个C头(每个头具有形式为name.h的名称),其行为就像是由相应cname头放置在标准库名称空间中的每个名称都位于全局名称空间范围内。这些名称是先在名称空间std的名称空间范围(3.3.6)中声明还是定义,然后通过显式using-声明(7.3.3)注入到全局名称空间范围中,这一点尚不确定。

因此,如果使用<cstdio>,可以确定,printf它将在中namespace std,因此不在全局名称空间中。
使用全局名称空间会产生名称冲突。这不是C ++方式。

因此,我正在使用<cstdio>标题,并建议您这样做。


4
尽管我希望它能以这种方式工作,但事实并非如此。如果包括<cstdio>你保证的std :: printf的会存在,但不能保证从如果:: printf的会或不会存在以及标准。实际上,在我曾经听说过的所有编译器中,当包含include时,:: printf 都会注入到全局名称空间中<cstdio>
wjl 2015年

3

根据我自己的实践:使用std::前缀。否则,如果使用浮点运算,有一天abs 非常痛苦地咬你。

不合格abs是指int在某些平台上定义的功能。在其他方面,它是超负荷的。但是,std::abs对于所有类型,总是过载。


2

仅使用printf不使用std::可能会产生一些名称冲突,并且被许多c ++开发人员视为不良做法。Google是您的朋友,但是这里有一些链接,希望对您有所帮助

为什么“使用命名空间标准”被认为是不好的做法? http://www.cplusplus.com/forum/beginner/61121/


4
using namespace std这是一种不好的做法,但使用printf不带std::限定符的方法则不是。
2015年

using namespace std;这不是我的问题。我从不使用它。printf();并且std::printf();可以在没有C的情况下工作,using namespace std;这就是为什么我发布了这个问题。
DeiDei

@REACHUS不同意。两种情况之间没有区别。
Konrad Rudolph 2015年

我永远不会使用std::printf它,只是感觉很奇怪。
trenki

@KonradRudolph我没有说有什么区别,我只是表达了自己的观点(更多理由请参见我的回答)。
2015年

2

在stdio

这是标准C库标头@c stdio.h的C ++版本,其内容(大部分)与该标头相同,但都包含在名称空间@c std中(除了在名称中定义为宏的名称) C)。

因此,它应该没有任何区别。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.