适应性
对printf
非POD的任何尝试都会导致不确定的行为:
struct Foo {
virtual ~Foo() {}
operator float() const { return 0.f; }
};
printf ("%f", Foo());
std::string foo;
printf ("%s", foo);
上面的printf-calls产生不确定的行为。您的编译器可能确实会警告您,但是这些警告不是标准所必需的,并且对于仅在运行时才知道的格式字符串是不可能的。
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:
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);
要么:
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");
I18N
我们重复使用我们的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的用户。这是功能,不是错误!
如果您始终使用iostream,则可以
std::ios::sync_with_stdio(false);
并通过良好的编译器获得相等的运行时:
#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";
}
结果(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
判断...你自己。
不,您不会禁止我打印。
借助可变参数模板,您可以在C ++ 11中为类型安全的I18N友好的printf设置字符。使用用户定义的文字,您将可以使它们具有非常出色的性能,即可以编写完全静态的化身。
我有一个概念证明。那时,对C ++ 11的支持还不如现在成熟,但是您有一个主意。
时间适应性
...
struct Frob {
unsigned int x;
};
...
... printf ("%u", frob.x); ...
... printf ("%u", frob.x); ...
... printf ("%u", frob.x); ...
... printf ("%u", frob.x); ...
后来,您的数据变得如此巨大,您必须做
...
unsigned long long x;
...
这是一个有趣的练习,它可以做到这一点并做到无错误。特别是当其他非耦合项目使用foo.h时。
其他。
printf
与C ++流不兼容。C ++流使您可以轻松地将控制台输出转换为文件。(尽管您可以使用进行类似操作fprintf
)。