我通常使用cout
和cerr
写文本到控制台.然而,有时我发现使用旧的printf
陈述更容易.我需要格式化输出时使用它.
我将使用它的一个例子是:
// Lets assume that I'm printing coordinates... printf("(%d,%d)\n", x, y); // To do the same thing as above using cout.... cout << "(" << x << "," << y << ")" << endl;
我知道我可以使用格式化输出,cout
但我已经知道如何使用printf
.有什么理由我不应该使用这个printf
陈述吗?
我的学生,谁学习cin
和cout
第一,然后学习printf
后,绝大多数喜欢printf
(或者更通常fprintf
).我自己已经发现该printf
模型具有足够的可读性,我已将其移植到其他编程语言中.所以有奥利维尔·丹维,谁已经连上了类型安全.
如果你有一个能够对类型进行类型检查的编译器printf
,我认为没有理由不在fprintf
C++中使用和朋友.
免责声明:我是一个可怕的C++程序员.
如果您希望自己的计划,请远离iostreams.问题是,如果句子由多个片段组成,就像使用iostream一样,就不可能正确地本地化你的字符串.
除了消息片段的问题,您还有一个订购问题.考虑一个打印学生姓名和平均成绩点的报告:
std::cout << name << " has a GPA of " << gpa << std::endl;
当您将其翻译成另一种语言时,另一种语言的语法可能需要您在名称前显示GPA.AFAIK,iostreams无法重新排序插值.
如果您想要两全其美(类型安全且能够使用i18n),请使用Boost.Format.
任何printf
非POD的尝试都会导致未定义的行为:
struct Foo { virtual ~Foo() {} operator float() const { return 0.f; } }; printf ("%f", Foo()); std::string foo; printf ("%s", foo);
上面的printf调用产生了未定义的行为.您的编译器可能会向您发出警告,但标准不要求这些警告,并且对于仅在运行时已知的格式字符串不可能.
IO流:
std::cout << Foo(); std::string foo; std::cout << foo;
判断自己.
struct Person { string first_name; string second_name; }; std::ostream& operator<< (std::ostream &os, Person const& p) { return os << p.first_name << ", " << p.second_name; } cout << p; cout << p; some_file << p;
C:
// inline everywhere printf ("%s, %s", p.first_name, p.second_name); printf ("%s, %s", p.first_name, p.second_name); fprintf (some_file, "%s, %s", p.first_name, p.second_name);
要么:
// re-usable (not common in my experience) int person_fprint(FILE *f, const Person *p) { return fprintf(f, "%s, %s", p->first_name, p->second_name); } int person_print(const Person *p) { return person_fprint(stdout, p); } Person p; .... person_print(&p);
注意如何在C中使用正确的调用参数/签名(例如person_fprint(stderr, ...
,person_fprint(myfile, ...
),在C++中,"- FILE
argument"自动从表达式"派生".这个推导的更精确等价实际上更像是这样的:
FILE *fout = stdout; ... fprintf(fout, "Hello World!\n"); person_fprint(fout, ...); fprintf(fout, "\n");
我们重用我们的Person定义:
cout << boost::format("Hello %1%") % p; cout << boost::format("Na %1%, sei gegrüßt!") % p; printf ("Hello %1$s, %2$s", p.first_name.c_str(), p.second_name.c_str()); printf ("Na %1$s, %2$s, sei gegrüßt!", p.first_name.c_str(), p.second_name.c_str());
判断自己.
我发现今天(2017年)的相关性较低.也许只是一种直觉,但I18N并不是普通C或C++程序员每天都能完成的事情.另外,无论如何,这都是一种痛苦.
你有没有测量过printf性能的实际意义?您的瓶颈应用是否严重如此懒惰以至于计算结果的输出是瓶颈?你确定你需要C++吗?
可怕的性能损失是为了满足那些想要混合使用printf和cout的人.这是一个功能,而不是一个错误!
如果你持续使用iostreams,你可以
std::ios::sync_with_stdio(false);
并通过良好的编译器获得相同的运行时间:
#include#include #include #include void ios_test (int n) { for (int i=0; i 结果(
g++ -O3 synced-unsynced-printf.cc
,./a.out > /dev/null
,cat RESULTS
):C ..............: 1.1 sec C++, sync with C: 1.76 sec C++, non-sync ..: 1.01 sec判断......你自己.
不,你不会禁止我的printf.
借助可变参数模板,您可以在C++ 11中使用类型安全的I18N友好printf.并且您将能够使用用户定义的文字非常,非常高效,即可以编写完全静态的化身.
我有一个概念证明.那时候,对C++ 11的支持并不像现在这样成熟,但是你有了一个想法.
时间适应性
// foo.h ... struct Frob { unsigned int x; }; ... // alpha.cpp ... printf ("%u", frob.x); ... // bravo.cpp ... printf ("%u", frob.x); ... // charlie.cpp ... printf ("%u", frob.x); ... // delta.cpp ... printf ("%u", frob.x); ...之后,您的数据变得如此之大,您必须这样做
// foo.h ... unsigned long long x; ...这是一个有趣的练习,可以保持这种无错误.特别是当其他非耦合项目使用foo.h时.
其他.
Bug潜力:使用printf会有很多空间来提交错误,特别是当你在混合中输入用户输入基础字符串时(想想你的I18N团队).你必须注意正确地转义每个这样的格式字符串,你必须确保传递正确的参数等等.
IO-Streams使我的二进制文件更大:如果这是一个比可维护性,代码质量,可重用性更重要的问题,那么(在验证问题之后!)使用printf.
现代编译器诊断格式规范和参数之间的不匹配.
4> Igor Zevaka..:我使用printf因为我讨厌丑陋的
<
语法.
还有什么更好的理由?:P
5> janm..:使用boost :: format.你得到类型安全,std :: string支持,类似接口的printf,使用cout的能力,以及许多其他好东西.你不会回去.
6> mingos..:没有理由.我认为只是一些奇怪的意识形态驱使人们只使用C++库,即使旧的C lib仍然有效.我是一个C++人,我也使用C函数.从来没有遇到任何问题.
c库质量非常好,而且易于使用.我同意人们不应该感到有压力使用c ++库.
7> GManNickG..:流是规范的方式.尝试使用此代码
printf
:templatevoid output(const T& pX) { std::cout << pX << std::endl; } 祝好运.
我的意思是,你可以让操作员允许输出你的类型
ostream
,而不用麻烦就像任何其他类型一样使用它.printf
不符合C++的一般性,或更具体的模板.不仅仅是可用性.还有一致性.在我的所有项目中,我都有cout(
cerr
和clog
)tee'd也输出到文件.如果您使用printf
,则跳过所有这些.此外,一致性本身是一件好事; 混合cout
和printf
,而完全有效的,是丑陋的.如果你有一个对象,并且想要使它成为可输出的,那么最简洁的方法就是
operator<<
为该类重载.那你打算怎么用printf
?你会用混乱的代码最终cout
的和printf
的.如果您真的想要格式化,请在维护流接口的同时使用Boost.Format.一致性和格式.
你没有被投票,因为你有一个真正的观点,你的投票是因为你的观点无关紧要.我们知道`printf`不能这样做,它不是为了设计的.这就好说,"哦,我打赌你不能用C语言上课".这一点也是正确的,因为语言不是为了设计的.
这几乎无关紧要.你问是否应该使用`printf`.为保持一致性,**不**.Streams将始终有效,`printf`并不总是有效.不一致的代码很难看.如果我有'cout` tee'd也打印到日志文件怎么办?(是的,我的所有项目都是这样做的!)现在你只是绕过了这一切.除了保存击键之外,还有更多要考虑的问题.
8> cuteCAT..:使用printf.不要使用C++流.printf为您提供了更好的控制(例如浮动精度等).代码通常也更短,更易读.
谷歌C++风格指南同意.
除了日志记录界面要求之外,不要使用流.请改用类似printf的例程.
使用流有各种各样的利弊,但在这种情况下,与许多其他情况一样,一致性胜过辩论.不要在代码中使用流.
9> Martin Becke..:总的来说我同意(讨厌<<语法,特别是如果你需要复杂的格式)
但我应该指出安全方面.
printf("%x",2.0f) printf("%x %x",2) printf("%x",2,2)可能不会被编译器注意到,但可能会使您的应用程序崩溃.