我应该在我的 C++ 代码中使用 printf 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2017489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should I use printf in my C++ code?
提问by Bob Dylan
I generally use cout
and cerr
to write text to the console. However sometimes I find it easier to use the good old printf
statement. I use it when I need to format the output.
我通常使用cout
和cerr
将文本写入控制台。然而,有时我发现使用好的旧printf
语句更容易。我在需要格式化输出时使用它。
One example of where I would use this is:
我将使用它的一个例子是:
// 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;
I know I can format output using cout
but I already know how to use the printf
. Is there any reason I shouldn't use the printf
statement?
我知道我可以使用格式化输出,cout
但我已经知道如何使用printf
. 有什么理由我不应该使用该printf
语句吗?
回答by Norman Ramsey
My students, who learn cin
and cout
first, then learn printf
later, overwhelmingly prefer printf
(or more usually fprintf
). I myself have found the printf
model sufficiently readable that I have ported it to other programming languages. So has Olivier Danvy, who has even made it type-safe.
我的学生,谁学习cin
和cout
第一,然后学习printf
后,绝大多数喜欢printf
(或者更通常fprintf
)。我自己发现该printf
模型具有足够的可读性,因此我已将其移植到其他编程语言中。所以有奥利维尔·丹维,谁已经连上了类型安全。
Provided you have a compiler that is capable of type-checking calls to printf
, I see no reason not to use fprintf
and friends in C++.
如果您有一个能够对 调用进行类型检查的编译器printf
,我认为没有理由不使用fprintf
C++ 中的朋友。
Disclaimer:I am a terrible C++ programmer.
免责声明:我是一个糟糕的 C++ 程序员。
回答by R Samuel Klatchko
If you ever hope to i18n your program, stay away from iostreams. The problem is that it can be impossible to properly localize your strings if the sentence is composed of multiple fragments as is done with iostream.
如果您希望对您的程序进行 i18n,请远离 iostreams。问题是,如果句子像使用 iostream 那样由多个片段组成,则不可能正确本地化您的字符串。
Besides the issue of message fragments, you also have an issue of ordering. Consider a report that prints a student's name and their grade point average:
除了消息片段的问题,您还有一个排序问题。考虑一个打印学生姓名及其平均成绩的报告:
std::cout << name << " has a GPA of " << gpa << std::endl;
When you translate that to another language, the other language's grammar may need you to show the GPA before the name. AFAIK, iostreams has not way to reorder the interpolated values.
当您将其翻译成另一种语言时,另一种语言的语法可能需要您在名称前显示 GPA。AFAIK,iostreams 无法重新排序插值。
If you want the best of both worlds (type safety and being able to i18n), use Boost.Format.
如果您想要两全其美(类型安全和能够 i18n),请使用Boost.Format。
回答by Sebastian Mach
Adaptability
适应性
Any attempt to printf
a non-POD results in undefined behaviour:
任何对printf
非 POD 的尝试都会导致未定义的行为:
struct Foo {
virtual ~Foo() {}
operator float() const { return 0.f; }
};
printf ("%f", Foo());
std::string foo;
printf ("%s", foo);
The above printf-calls yield undefined behaviour. Your compiler may warn you indeed, but those warnings are not required by the standards and not possible for format strings only known at runtime.
上面的 printf 调用产生未定义的行为。您的编译器确实可能会警告您,但这些警告不是标准所要求的,并且对于仅在运行时已知的格式字符串是不可能的。
IO-Streams:
IO 流:
std::cout << Foo();
std::string foo;
std::cout << foo;
Judge yourself.
自己判断吧。
Extensibility
可扩展性
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:
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);
or:
或者:
// 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);
Note how you have to take care of using the proper call arguments/signatures in C (e.g. person_fprint(stderr, ...
, person_fprint(myfile, ...
), where in C++, the "FILE
-argument" is automatically "derived" from the expression. A more exact equivalent of this derivation is actually more like this:
请注意您必须如何在 C 中使用正确的调用参数/签名(例如person_fprint(stderr, ...
, person_fprint(myfile, ...
),其中在 C++ 中,“- FILE
argument”自动从表达式“派生”。这种推导更精确的等价物实际上更像这样:
FILE *fout = stdout;
...
fprintf(fout, "Hello World!\n");
person_fprint(fout, ...);
fprintf(fout, "\n");
I18N
18N
We reuse our Person definition:
我们重用我们的 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());
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());
Judge yourself.
自己判断吧。
I find this less relevant as of today (2017). Maybe just a gut feeling, but I18N is not something that is done on a daily basis by your average C or C++ programmer. Plus, it's a pain in the a...natomy anyways.
我发现这与今天(2017 年)不太相关。也许只是一种直觉,但 I18N 并不是普通 C 或 C++ 程序员每天都在做的事情。另外,无论如何,这在解剖学上是一种痛苦。
Performance
表现
- Have you measured the actual significance of printf performance? Are your bottleneck applications seriously so lazy that the output of computation results is a bottleneck? Are you sure you need C++ at all?
- The dreaded performance penalty is to satisfy those of you who want to use a mix of printf and cout. It is a feature, not a bug!
- 你测量过 printf 性能的实际意义吗?您的瓶颈应用程序是否严重懒惰以致计算结果的输出成为瓶颈?你确定你需要 C++ 吗?
- 可怕的性能损失是为了满足那些想要混合使用 printf 和 cout 的人。这是一个功能,而不是一个错误!
If you use iostreams consistently, you can
如果您始终如一地使用 iostreams,则可以
std::ios::sync_with_stdio(false);
and reap equal runtime with a good compiler:
并使用一个好的编译器获得相同的运行时间:
#include <cstdio>
#include <iostream>
#include <ctime>
#include <fstream>
void ios_test (int n) {
for (int i=0; i<n; ++i) {
std::cout << "foobarfrob" << i;
}
}
void c_test (int n) {
for (int i=0; i<n; ++i) {
printf ("foobarfrob%d", i);
}
}
int main () {
const clock_t a_start = clock();
ios_test (10024*1024);
const double a = (clock() - a_start) / double(CLOCKS_PER_SEC);
const clock_t p_start = clock();
c_test (10024*1024);
const double p = (clock() - p_start) / double(CLOCKS_PER_SEC);
std::ios::sync_with_stdio(false);
const clock_t b_start = clock();
ios_test (10024*1024);
const double b = (clock() - b_start) / double(CLOCKS_PER_SEC);
std::ofstream res ("RESULTS");
res << "C ..............: " << p << " sec\n"
<< "C++, sync with C: " << a << " sec\n"
<< "C++, non-sync ..: " << b << " sec\n";
}
Results (g++ -O3 synced-unsynced-printf.cc
, ./a.out > /dev/null
, cat RESULTS
):
结果 ( 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
Judge ... yourself.
判断......你自己。
No. You won't forbid me my printf.
不,你不会禁止我使用我的 printf。
You can haz a typesafe, I18N friendly printf in C++11, thanks to variadic templates. And you will be able to have them very, very performant using user-defined literals, i.e. it will be possible to write a fully static incarnation.
由于可变参数模板,您可以在 C++11 中使用类型安全、I18N 友好的 printf。并且您将能够使用用户定义的文字使它们非常非常高效,即可以编写完全静态的化身。
I have a proof of concept. Back then, support for C++11 was not as mature as it is now, but you get an idea.
我有一个概念证明。那时,对 C++11 的支持还没有现在那么成熟,但您应该有一个想法。
Temporal Adaptability
时间适应性
// 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); ...
Later, your data grows so big you must do
后来,您的数据变得如此之大,您必须这样做
// foo.h
...
unsigned long long x;
...
It is an interesting exercise maintaining that and doing it bug-free. Especially when other, non-coupled projects use foo.h.
这是一个有趣的练习,可以保持并做到无错误。特别是当其他非耦合项目使用foo.h 时。
Other.
其他。
Bug Potential: There's a lot of space to commit mistakes with printf, especially when you throw user input bases strings in the mix (think of your I18N team). You must take care to properly escape every such format string, you must be sure to pass the right arguments, etc. etc..
IO-Streams make my binary bigger: If this is a more important issue than maintainability, code-quality, reuseability, then (after verifying the issue!) use printf.
潜在错误: printf 有很大的空间可以犯错误,尤其是当您将用户输入基础字符串混入时(想想您的 I18N 团队)。您必须注意正确转义每个此类格式字符串,您必须确保传递正确的参数等。
IO-Streams 使我的二进制文件更大:如果这是一个比可维护性、代码质量、可重用性更重要的问题,那么(在验证问题之后!)使用 printf。
回答by Igor Zevaka
I use printf because I hate the ugly <<cout<<
syntax.
我使用 printf 是因为我讨厌丑陋的<<cout<<
语法。
回答by janm
Use boost::format. You get type safety, std::string support, printf like interface, ability to use cout, and lots of other good stuff. You won't go back.
使用 boost::format。您可以获得类型安全、std::string 支持、类似 printf 的接口、使用 cout 的能力以及许多其他好东西。你不会回去。
回答by mingos
No reason at all. I think it's just some strange ideology that drives people towards using only C++ libraries even though good old C libs are still valid. I'm a C++ guy and I use C functions a lot too. Never had any problems with them.
完全没有理由。我认为这只是一些奇怪的意识形态,驱使人们只使用 C++ 库,即使好的旧 C 库仍然有效。我是一个 C++ 人,我也经常使用 C 函数。他们从来没有遇到过任何问题。
回答by GManNickG
Streams are the canonical way. Try making this code work with printf
:
流是规范的方式。尝试使此代码与printf
:
template <typename T>
void output(const T& pX)
{
std::cout << pX << std::endl;
}
Good luck.
祝你好运。
What I mean is, you can make operators to allow your types to be outputted to ostream
's, and without hassle use it just like any other type. printf
doesn't fit the the generality of C++, or more specifically templates.
我的意思是,您可以让运算符允许您的类型输出到ostream
's,并且可以像使用任何其他类型一样轻松地使用它。printf
不适合 C++ 的通用性,或者更具体的模板。
There's more than usability. There's also consistency. In all my projects, I have cout (and cerr
and clog
) tee'd to also output to a file. If you use printf
, you skip all of that. Additionally, consistency itself is a good thing; mixing cout
and printf
, while perfectly valid, is ugly.
不仅仅是可用性。还有一致性。在我所有的项目中,我都有 cout(cerr
和clog
) tee 也输出到文件。如果使用printf
,则跳过所有这些。此外,一致性本身是一件好事;混合cout
and printf
,虽然完全有效,但很丑陋。
If you have an object, and you want to make it output-able, the cleanest way to do this is overload operator<<
for that class. How are you going to use printf
then? You're going to end up with code jumbled with cout
's and printf
's.
如果您有一个对象,并且希望使其可输出,那么最简洁的方法是operator<<
对该类进行重载。那你打算怎么用printf
?你最终会得到与cout
's 和printf
's混淆的代码。
If you really want formatting, use Boost.Format while maintaining the stream interface. Consistency andformatting.
如果您真的想要格式化,请在保持流接口的同时使用 Boost.Format。一致性和格式。
回答by cuteCAT
Use printf. Do not use C++ streams. printf gives you much better control (such as float precision etc.). The code is also usually shorter and more readable.
使用printf。不要使用 C++ 流。printf 为您提供更好的控制(例如浮点精度等)。代码通常也更短且更具可读性。
Google C++ style guideagrees.
谷歌 C++ 风格指南同意。
Do not use streams, except where required by a logging interface. Use printf-like routines instead.
There are various pros and cons to using streams, but in this case, as in many other cases, consistency trumps the debate. Do not use streams in your code.
不要使用流,除非日志接口需要。改用类似 printf 的例程。
使用流有各种优点和缺点,但在这种情况下,与许多其他情况一样,一致性胜过辩论。不要在代码中使用流。
回答by Martin Beckett
On the whole I agree (hate the << syntax especially if you need complex formatting)
总的来说,我同意(讨厌 << 语法,特别是如果您需要复杂的格式)
But I should point out the safety aspects.
但我应该指出安全方面。
printf("%x",2.0f)
printf("%x %x",2)
printf("%x",2,2)
Probably won't be noticed by the compiler but could crash your app.
编译器可能不会注意到,但可能会使您的应用程序崩溃。
回答by Bob Jarvis - Reinstate Monica
Use whatever fits your needs and preferences. If you're comfortable with printf then by all means use it. If you're happier with iostreams stick to 'em. Mix and match as best fits your requirements. This is software, after all - there's better ways and worse ways, but seldom is there only ONE way.
使用适合您的需求和偏好的任何东西。如果您对 printf 感到满意,那么一定要使用它。如果您对 iostreams 感到满意,请坚持使用它们。混合搭配最适合您的要求。毕竟这是软件 - 有更好的方法和更坏的方法,但很少只有一种方法。
Share and enjoy.
分享和享受。