C格式化I/O函数(如printf、sprintf等)比IOStream更受欢迎,如果是这样的话,为什么?

17

最近我一直在查看很多别人编写的代码,注意到大家经常使用“printf”样式的C函数,但是在学校学习的C++函数(特别是cout)似乎不太流行。

这个观察是否正确?有什么原因吗?惯例吗?

谢谢,

R


9
“Everybody”似乎有点过度绝对化的说法。 - Martin York
另请参见:https://dev59.com/knVD5IYBdhLWcg3wAWoO#119194 - Martin York
谁是每个人,你不应该做出如此广泛的假设。 - user195488
他说的完全正确。这是因为iostreams太糟糕了,甚至让C ++程序员哭泣,而他们已经习惯了垃圾代码 :) - Matt Joiner
我只使用 iostreams 进行输入、输出或格式化。它们有其特点,但至少是类型安全的。 - Matthieu M.
6个回答

24

个人而言,我更倾向使用 printf 而不是像 cout 这样的 iostream 工具,因为我认为它更加清晰。

当你使用 iostream 进行格式化时,你需要使用各种奇怪的东西,比如 setiosflagssetf。我总是记不住这些东西存放在哪个命名空间中,更不用说所有这些都是做什么的了。即使我记得,我也会对代码显得冗长和不直观感到失望。

printf 的格式选项可能一开始看起来难以读懂,但它们简洁,并且在单个手册页面中有清晰的文档,并且是许多语言共有的。

另一个优点是 printf 是无状态的:与 cout 不同,我不需要记住哪些成员函数已经在 printf 上调用过,或者哪种复杂的标志组合被插入到其中。这对于可读性来说是一个很大的优势。


11
+1 因指出有状态与无状态之分。当您无需担心输出数据会相互干扰时,这确实是一件美妙的事情。 - JustJeff
6
需要翻译的内容:One thing to point out as well is that you can use printf-style flags with C++ strings using boost::format。可以使用 boost::format 在 C++ 字符串中使用 printf 风格的标志。 - bdonlan

6

我认为口味是可能的原因之一。就我个人而言,我发现这样:

printf("%8d: %s\n", customer->id, customer->name);

比这个更易读:
std::cout << customer->id << ": " << customer->name << std::endl;

还有本地化的问题。使用printf可以更改格式以适应其他语言和UI文化,而使用iostreams则变得非常繁琐,除非您使用类似Boost Format库这样的东西。


奇怪的答案。实际上,对于语言环境的支持是 iostream 比 printf 显着更好的一个方面,并且使用起来并不真正更难。 - Martin Ba

4

标准流系统存在一些批评,最值得注意的是它通常不如C语言的系统高效,并且它们不允许重新排序要格式化的项目,这可能会使本地化更加困难。

个人而言,我大多数情况下都使用流,因为它们允许我在不修改函数的情况下将函数写入控制台、文件或字符串。


4
你知道吗,你可以在使用boost::format时使用带有printf格式说明符的流 :) - bdonlan
2
FILE*作为参数传递与传递ostream参数一样容易。这允许fprintf写入控制台或文件。 - gwell
2
@gwell:据我所知,我无法让FILE*写入内存缓冲区。 - Billy ONeal
1
@Billy ONeal,再看一遍,这些东西是存在的! - Matt Joiner
GNU库支持fmemopen()。虽然它不是标准,但它确实存在。请参见http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_11.html#SEC166。 - gwell
显示剩余2条评论

2

对于良好的交叉引用,点赞。 - Jonathan Leffler

0
printf和scanf系列函数存在两个主要问题:类型安全和内存安全。很容易在规范字符串和后续可变长度参数列表之间产生不匹配。而且,通过scanf造成的缓冲区溢出是经典的安全漏洞。简而言之,不要使用它们。
C ++流提供类型和内存安全,还具有格式扩展性。它们比printf和scanf更强大,通常更容易使用。
此外,正如ShaderOp建议的那样,Boost的格式库提供了相同的安全性,但可以让老式C程序员感觉更舒适。

1
C ++足够低级,以至于即使使用流和“类型安全”,您也始终可以在脚上开枪,例如 cout << *(int *)&foo;。另一方面,任何像样的C编译器都会针对printf格式字符串类型不匹配发出警告,因此我认为'safety'不是一个有效的论点。另一方面,与printf相比,C ++流至少具有两个主要缺点:易于将消息本地化以进行翻译,并且无状态性(在线程中可能是一个大问题)。 - R.. GitHub STOP HELPING ICE
编译器只有在知道格式字符串是什么时才能验证它。但是,与iostream相比,printf的优点之一是您可以在运行时设置格式字符串。因此,类型安全性对我来说肯定是一个有效的论点。 - Dennis Zickefoose
3
任何合格的C++编译器都会捕捉到C风格的类型转换并发出警告。 - Sam Miller
1
@Dennis:任何在运行时构建格式化字符串的人(除了加载国际化版本)都需要被枪毙(因为安全漏洞,如果没有其他原因)。 - Billy ONeal
@Dennis:最好有一些验证过程来检查国际化版本是否与原始版本匹配 :) - Matthieu M.
显示剩余3条评论

0

我猜printf更广泛使用是因为:

  • 在C++编译器和流出现之前,它已经使用了相当多的年份
  • C比C++更常用
  • 许多I/O操作是为像Windows API这样的东西而进行的,其中printf是Open/Read/Write/Close等自然适合的一种

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接