当前位置:  开发笔记 > 编程语言 > 正文

我应该在我的C++代码中使用printf吗?

如何解决《我应该在我的C++代码中使用printf吗?》经验,为你挑选了9个好方法。

我通常使用coutcerr写文本到控制台.然而,有时我发现使用旧的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陈述吗?



1> Norman Ramse..:

我的学生,谁学习cincout第一,然后学习printf后,绝大多数喜欢printf(或者更通常fprintf).我自己已经发现该printf模型具有足够的可读性,我已将其移植到其他编程语言中.所以有奥利维尔·丹维,谁已经连上了类型安全.

如果你有一个能够对类型进行类型检查的编译器printf,我认为没有理由不在fprintfC++中使用和朋友.

免责声明:我是一个可怕的C++程序员.


我经常使用Java的`String.format`.在C++中,我使用Boost.Format很多,这对iostreams友好,但也有点'printf`兼容.
*printf缺乏类型安全性可以减轻,但不会被检查这些调用的编译器消除,因为使用变量作为格式字符串是一个完全有效的用例.例如:i18n.这个功能可以在很多方面爆炸,甚至都不好笑.我只是不再使用它了.我们可以访问完美的格式化程序,例如boost :: format或Qt :: arg.
@Norman Ramsey:我多次提到`printf()`的'类型安全问题'.*printf()究竟是什么类型的安全问题?*

2> R Samuel Kla..:

如果您希望自己的计划,请远离iostreams.问题是,如果句子由多个片段组成,就像使用iostream一样,就不可能正确地本地化你的字符串.

除了消息片段的问题,您还有一个订购问题.考虑一个打印学生姓名和平均成绩点的报告:

std::cout << name << " has a GPA of " << gpa << std::endl;

当您将其翻译成另一种语言时,另一种语言的语法可能需要您在名称前显示GPA.AFAIK,iostreams无法重新排序插值.

如果您想要两全其美(类型安全且能够使用i18n),请使用Boost.Format.


但是`boost :: format`为你提供了类型安全的细节.`printf`爆炸了.
@Ferruccio - 这也可以通过`printf()`来完成.
在boost :: format()中按位置指定格式化参数的能力非常适合本地化.
很好的答案.只是想补充一点,Boost格式的替代品可以快几倍,同时提供相同的安全级别:https://github.com/vitaut/format和https://github.com/c42f/tinyformat

3> Sebastian Ma..:

适应性

任何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++中,"- FILEargument"自动从表达式"派生".这个推导的更精确等价实际上更像是这样的:

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:

template 
void output(const T& pX)
{
    std::cout << pX << std::endl;
}

祝好运.

我的意思是,你可以让操作员允许输出你的类型ostream,而不用麻烦就像任何其他类型一样使用它.printf不符合C++的一般性,或更具体的模板.

不仅仅是可用性.还有一致性.在我的所有项目中,我都有cout(cerrclog)tee'd也输出到文件.如果您使用printf,则跳过所有这些.此外,一致性本身是一件好事; 混合coutprintf,而完全有效的,是丑陋的.

如果你有一个对象,并且想要使它成为可输出的,那么最简洁的方法就是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)

可能不会被编译器注意到,但可能会使您的应用程序崩溃.

推荐阅读
mobiledu2402851173
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有