在新C++的代码,我倾向于使用C++法师的图书馆,而不是C stdio图书馆。

我注意到一些程序似乎坚持stdio,坚持认为它是更便于携带。

这是真的吗?什么是更好地使用?

有帮助吗?

解决方案

回答原来的问题:
任何可以使用stdio可以通过使用法师的图书馆。

Disadvantages of iostreams: verbose
Advantages    of iostreams: easy to extend for new non POD types.

的前进步骤C++过C类型的安全。

  • iostreams的目的是要明确类型的安全。因此,分配的对象明确的检查类型(在编译器的时候)的目被分配过(生成编制的时间错误,如果需要的话)。因此,防止运行时存在运行或者编写一个浮动价值char对象等。

  • scanf()/printf()以及家庭在另一方面依靠的程序得到的格式串正确的,并没有类型检查(我认为,海湾合作委员会已经扩展,可以帮助).因此,它是源的许多错误(作为程序是不完美他们的分析比编译器,[不会说的编译器完美的只比人类更好]).

只是为了澄清意见,从科林*詹森。

  • 该法师图书馆已经稳定,因为释放最后的标准(我忘了实际年,但是大约10年前)。

澄清意见通过Mikael Jansson.

  • 其他语言,他提到,使用的格式风格有明确的保障措施,以防止危险的侧影响C stdio库,可以(C,但是没有提到语言)导致运行时间崩溃。

N.B。 我同意,法师的图书馆是一个冗长的一侧。但我愿意把verboseness,以确保运行安全。但是,我们可以减轻的详细程度可通过使用 提高格式的图书馆.

#include <iostream>
#include <iomanip>
#include <boost/format.hpp>

struct X
{  // this structure reverse engineered from
   // example provided by 'Mikael Jansson' in order to make this a running example

    char*       name;
    double      mean;
    int         sample_count;
};
int main()
{
    X   stats[] = {{"Plop",5.6,2}};

    // nonsense output, just to exemplify

    // stdio version
    fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
            stats, stats->name, stats->mean, stats->sample_count);

    // iostream
    std::cerr << "at " << (void*)stats << "/" << stats->name
              << ": mean value " << std::fixed << std::setprecision(3) << stats->mean
              << " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
              << " samples\n";

    // iostream with boost::format
    std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
                % stats % stats->name % stats->mean % stats->sample_count;
}

其他提示

这太冗长了。

考虑使用iostream构造来执行以下操作(类似于scanf):

// nonsense output, just to examplify
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
    stats, stats->name, stats->mean, stats->sample_count);

这需要以下内容:

std::cerr << "at " << static_cast<void*>(stats) << "/" << stats->name
          << ": mean value " << std::precision(3) << stats->mean
          << " of " << std::width(4) << std::fill(' ') << stats->sample_count
          << " samples " << std::endl;

字符串格式化是一种情况,面向对象可以而且应该回避有利于嵌入字符串的格式化DSL。考虑Lisp的format,Python的printf样式格式,或PHP,Bash,Perl,Ruby及其字符串插值。

该用例的

iostream充其量是错误的。

提升格式库为printf样式的字符串格式化提供了一种类型安全,面向对象的替代方案,并且是iostream的补充,由于巧妙地使用了operator%,因此不会出现通常的冗长问题。如果您不喜欢使用iostream的运算符<!> lt; <!> lt;。

,请考虑使用普通C printf。

回到过去的糟糕时期,C ++标准委员会一直在使用语言,而iostreams是一个不断变化的目标。如果您使用了iostream,那么您每年都有机会重写部分代码。因此,我总是使用自1989年以来没有显着变化的stdio。

如果我今天做的话,我会使用iostreams。

如果像我一样,在学习C ++之前学过C,那么stdio库看起来更自然。 iostream vs. stdio有利有弊,但在使用iostream时我确实错过了printf()。

原则上我会使用iostreams,在实践中我做了太多的格式化小数等,这使得iostreams太难以理解,所以我使用了stdio。 Boost :: format是一种改进,但对我来说还不够激励。实际上,stdio几乎是类型安全的,因为大多数现代编译器都会进行参数检查。

这是一个我对任何解决方案都不满意的领域。

对于二进制IO,我倾向于使用stdio的fread和fwrite。对于格式化的东西,我通常会使用IO Stream,虽然正如Mikael所说,非trival(非默认?)格式可以是PITA。

我会比较两种主流的图书馆从C++标准图书馆。

你不应该使用C-风格的格式基于字符串串的处理程在C++。

几个原因,存在麻省理工学院他们使用:

  • 不类型安全
  • 你可以不通过非POD类型以可变的参数列表(即,既不scanf+co., 也不printf+co.), 或者你进入黑暗的据点未定义的行为
  • 容易得到错误的:
    • 你必须管理保留的格式和串的"价值的参数列表"同步
    • 你必须保持同步 正确

细微的错误介绍了在遥远的地方

它不仅是printf在本身就是不好的。软件获得老是重组和改和错误可能引入偏远的地方。假设你已经

.

// foo.h
...
float foo;
...

和某个地方...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

三年后你找到那foo应的一些定义的类型...

// foo.h
...
FixedPoint foo;
...

但在某个地方...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

...然后你的老printf/scanf仍将汇编,除了,你现在得随机segfaults和你不记得为什么。

详细的iostreams

如果你认为printf()小详细,那么有一定的概率,你不要使用他们的法师的全部力量。例如:

  printf ("My Matrix: %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n",
          mat(0,0), mat(0,1), mat(0,2), mat(0,3), 
          mat(1,0), mat(1,1), mat(1,2), mat(1,3), 
          mat(2,0), mat(2,1), mat(2,2), mat(2,3), 
          mat(3,0), mat(3,1), mat(3,2), mat(3,3));

与此相比,使用iostreams的权利:

cout << mat << '\n';

你必须限定一个适当的载于操作者<< 它已经大体结构的printf的东西,但显着的区别是,你现在有什么重复使用和类型安全;当然你也可以做的东西重新用于printf-喜欢,但你必须printf再次(如果有什么你替换矩阵成员与新的 FixedPoint?), 除了其他非琐事,例如你必须通过文件*处理的周围。

C-格式风格的字符串不是更好地为I18N于iostreams

注意格式串通常以为的正在救援用国际化,但是它们没有更好的比法师在这方面:

printf ("Guten Morgen, Sie sind %f Meter groß und haben %d Kinder", 
        someFloat, someInt);

printf ("Good morning, you have %d children and your height is %f meters",
        someFloat, someInt); // Note: Position changed.

// ^^ not the best example, but different languages have generally different
//    order of "variables"

即, 旧风格的C格式串缺位置的信息尽iostreams做。

你也许想要考虑的 加强:格式, 所提供的支持,说明位置的格式串明确。从他们的实例部分:

cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.

一些printf实现提供位置的论点,但他们是非的标准。

我应该 从来没有 使用C-格式风格的字符串?

除了性能的(如指出的,由Jan邬达克),我没有看到一个原因。但请记住:

"我们应该忘记小的效率,说大约97%的时间:过早的最优化的根源的所有邪恶。然而,我们不应该通过我们机会在这一关键的3%。一个优秀的程序员将不会被哄骗到自满,通过这种推理,他将明智的仔细看的关键码;但是,只有在代码已被鉴定"-Knuth

"瓶颈发生在令人惊讶的地方,因此不要试图猜测,放在一个速破解到你已经证明那是瓶颈。" -派克

是的,printf实现是通常快于iostreams通常快于加强:格式(从一个小型的和具体的基准我写的,但它应该在很大程度上取决于情况,特别是:如果printf=100%,那么法师=160%,并提高::format=220%)

但是不要盲目省略考虑:多少时间做你 真的 花在文本处理?多久没有你的程序运行在退出之前?它是有关在所有回落到C-格式风格的字符串的、松散的类型安全,减少refactorbility, 增加的概率非常微妙的错误,可能会隐瞒自己的年和可能仅揭示自己的权利 进入你的最爱的客户的脸?

就个人而言,我不会回来如果我不能获得超过20%的加速比。但因为我的应用程序 花费几乎所有时间上的其他任务比串的处理,我从来没有过。一些分析程序 我写了花费几乎所有的时间在串处理,但它们的总运行时是那么小 它不值得的测试和核查的努力。

一些谜语

最后,我想预设的一些谜语:

找出所有错误,因为编译器不会(他只能建议如果他是很好的):

shared_ptr<float> f(new float);
fscanf (stdout, "%u %s %f", f)

如果没有别的,有什么错这个吗?

const char *output = "in total, the thing is 50%"
                     "feature  complete";
printf (output);

虽然C ++ iostreams API有很多好处,但一个重要的问题是i18n。问题是参数替换的顺序可以根据文化而变化。经典的例子是:

// i18n UNSAFE 
std::cout << "Dear " << name.given << ' ' << name.family << std::endl;

虽然这适用于英语,但在中文中,姓氏是第一位的。

在为国外市场翻译代码时,翻译片段充满了危险,因此新的l10ns可能需要更改代码而不仅仅是不同的字符串。

boost :: format似乎结合了最好的stdio(单个格式字符串,可以使用不同顺序的参数然后出现)和iostreams(类型安全性,可扩展性)。

我使用iostreams,主要是因为这样可以让以后更容易摆弄流(如果我需要的话)。例如,您可能会发现要在某个跟踪窗口中显示输出 - 这对cout和cerr来说相对容易。当然,你可以在unix上摆弄管道和东西,但这不是那么便携。

我喜欢类似printf的格式,所以我通常首先格式化一个字符串,然后将其发送到缓冲区。使用Qt,我经常使用 QString :: sprintf (尽管他们建议使用< a href =“http://doc.trolltech.com/4.4/qstring.html#arg-10”rel =“nofollow noreferrer”> QString :: arg 。我查看了 boost.format 同样,但是不能真正习惯语法(太多%了)。不过,我应该看看它。

我想念的iolibraries是格式化的输入。

iostreams没有很好的方法来复制scanf(),甚至boost也没有输入所需的扩展名。

stdio更适合读取二进制文件(比如将扩展块放入向量<!> lt; unsigned char <!> gt;并使用.resize()等)。请参阅 http://nuwen.net/libnuwen.html 中的file.hh中的read_rest函数。示例

当读取二进制文件导致虚假的eof时,C ++流可能会扼杀大量字节。

由于iostream已成为标准,因此您应该使用它们,因为您知道您的代码可以使用较新版本的编译器。我想现在大多数编译器都非常了解iostreams,使用它们应该没有任何问题。

但是如果你想坚持使用* printf函数,我认为没有任何问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top