C++ 中的“printf”与“cout”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2872543/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:20:30  来源:igfitidea点击:

'printf' vs. 'cout' in C++

c++printfiostreamcoutstdio

提问by hero

What is the difference between printf()and coutin C++?

在 C++ 中printf()cout在 C++ 中有什么区别?

回答by Konrad Borowski

I'm surprised that everyone in this question claims that std::coutis way better than printf, even if the question just asked for differences. Now, there is a difference - std::coutis C++, and printfis C (however, you can use it in C++, just like almostanything else from C). Now, I'll be honest here; both printfand std::couthave their advantages.

我很惊讶这个问题中的每个人都声称这std::cout比 好得多printf,即使这个问题只是要求有所不同。现在,有一个区别 -std::cout是 C++,printf还是 C(但是,您可以在 C++ 中使用它,就像 C 中的几乎任何其他东西一样)。现在,我会在这里说实话;两者都有printfstd::cout各有优势。

Real differences

真正的差异

Extensibility

可扩展性

std::coutis extensible. I know that people will say that printfis extensible too, but such extension is not mentioned in the C standard (so you would have to use non-standard features - but not even common non-standard feature exists), and such extensions are one letter (so it's easy to conflict with an already-existing format).

std::cout是可扩展的。我知道人们会说它printf也是可扩展的,但是 C 标准中没有提到这样的扩展(所以你必须使用非标准特性——但甚至不存在常见的非标准特性),而且这样的扩展是一个字母(因此很容易与已经存在的格式发生冲突)。

Unlike printf, std::coutdepends completely on operator overloading, so there is no issue with custom formats - all you do is define a subroutine taking std::ostreamas the first argument and your type as second. As such, there are no namespace problems - as long you have a class (which isn't limited to one character), you can have working std::ostreamoverloading for it.

printf,std::cout完全取决于运算符重载,因此自定义格式没有问题 - 您所做的就是定义一个子例程std::ostream,将第一个参数作为第一个参数,将您的类型作为第二个参数。因此,不存在命名空间问题——只要您有一个类(不限于一个字符),您就可以对其进行std::ostream重载。

However, I doubt that many people would want to extend ostream(to be honest, I rarely saw such extensions, even if they are easy to make). However, it's here if you need it.

然而,我怀疑很多人会想要扩展ostream(说实话,我很少看到这样的扩展,即使它们很容易制作)。但是,如果您需要它,它就在这里。

Syntax

句法

As it could be easily noticed, both printfand std::coutuse different syntax. printfuses standard function syntax using pattern string and variable-length argument lists. Actually, printfis a reason why C has them - printfformats are too complex to be usable without them. However, std::coutuses a different API - the operator <<API that returns itself.

因为它可以很容易地发现,无论是printfstd::cout使用不同的语法。printf使用使用模式字符串和可变长度参数列表的标准函数语法。实际上,这printf是 C 拥有它们的一个原因——printf格式太复杂了,没有它们就无法使用。但是,std::cout使用不同的 API -operator <<返回自身的API。

Generally, that means the C version will be shorter, but in most cases it won't matter. The difference is noticeable when you print many arguments. If you have to write something like Error 2: File not found., assuming error number, and its description is placeholder, the code would look like this. Both examples work identically(well, sort of, std::endlactually flushes the buffer).

通常,这意味着 C 版本会更短,但在大多数情况下,这无关紧要。当您打印许多参数时,差异很明显。如果您必须编写类似Error 2: File not found.,假设错误编号,并且其描述是占位符,则代码将如下所示。两个示例的工作方式相同(好吧,std::endl实际上是刷新缓冲区)。

printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;

While this doesn't appear too crazy (it's just two times longer), things get more crazy when you actually format arguments, instead of just printing them. For example, printing of something like 0x0424is just crazy. This is caused by std::coutmixing state and actual values. I never saw a language where something like std::setfillwould be a type (other than C++, of course). printfclearly separates arguments and actual type. I really would prefer to maintain the printfversion of it (even if it looks kind of cryptic) compared to iostreamversion of it (as it contains too much noise).

虽然这看起来并不太疯狂(它只是长了两倍),但当您实际格式化参数而不是仅仅打印它们时,事情会变得更加疯狂。例如,打印类似的东西简直0x0424是疯了。这是由std::cout混合状态和实际值引起的。我从未见过一种语言将类似的东西std::setfill作为一种类型(当然,除了 C++)。printf明确区分参数和实际类型。printf与它的版本相比iostream(因为它包含太多噪音),我真的更愿意维护它的版本(即使它看起来有点神秘)。

printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;

Translation

翻译

This is where the real advantage of printflies. The printfformat string is well... a string. That makes it really easy to translate, compared to operator <<abuse of iostream. Assuming that the gettext()function translates, and you want to show Error 2: File not found., the code to get translation of the previously shown format string would look like this:

这才是真正的优势printf所在。该printf格式字符串是很好...字符串。与operator <<滥用iostream. 假设该gettext()函数进行了翻译,并且您想显示Error 2: File not found.,那么获取先前显示的格式字符串的翻译的代码将如下所示:

printf(gettext("Error %d: %s.\n"), id, errors[id]);

Now, let's assume that we translate to Fictionish, where the error number is after the description. The translated string would look like %2$s oru %1$d.\n. Now, how to do it in C++? Well, I have no idea. I guess you can make fake iostreamwhich constructs printfthat you can pass to gettext, or something, for purposes of translation. Of course, $is not C standard, but it's so common that it's safe to use in my opinion.

现在,让我们假设我们转换为 Fictionish,其中错误编号在描述之后。翻译后的字符串看起来像%2$s oru %1$d.\n. 现在,如何在 C++ 中做到这一点?好吧,我不知道。我想您可以伪造iostream哪些构造printf,您可以将其传递给gettext,或出于翻译目的。当然,$它不是 C 标准,但它很常见,在我看来它可以安全使用。

Not having to remember/look-up specific integer type syntax

不必记住/查找特定的整数类型语法

C has lots of integer types, and so does C++. std::couthandles all types for you, while printfrequires specific syntax depending on an integer type (there are non-integer types, but the only non-integer type you will use in practice with printfis const char *(C string, can be obtained using to_cmethod of std::string)). For instance, to print size_t, you need to use %zd, while int64_twill require using %"PRId64". The tables are available at http://en.cppreference.com/w/cpp/io/c/fprintfand http://en.cppreference.com/w/cpp/types/integer.

C 有很多整数类型,C++ 也是如此。std::cout为您处理所有类型,而printf根据整数类型需要特定语法(有非整数类型,但您在实践中将使用的唯一非整数类型printfconst char *(C 字符串,可以使用 )的to_c方法获得std::string)。例如,要打印size_t,您需要使用%zd,而int64_t将需要使用%"PRId64"。这些表格可从http://en.cppreference.com/w/cpp/io/c/fprintfhttp://en.cppreference.com/w/cpp/types/integer 获得

You can't print the NUL byte, \0

你不能打印 NUL 字节, \0

Because printfuses C strings as opposed to C++ strings, it cannot print NUL byte without specific tricks. In certain cases it's possible to use %cwith '\0'as an argument, although that's clearly a hack.

因为printf使用 C 字符串而不是 C++ 字符串,所以它不能在没有特定技巧的情况下打印 NUL 字节。在某些情况下,可以将%cwith'\0'用作参数,尽管这显然是一种黑客攻击。

Differences nobody cares about

没人关心的差异

Performance

表现

Update: It turns out that iostreamis so slow that it's usually slower than your hard drive (if you redirect your program to file). Disabling synchronization with stdiomay help, if you need to output lots of data. If the performance is a real concern (as opposed to writing several lines to STDOUT), just use printf.

更新:事实证明它iostream太慢了,它通常比你的硬盘慢(如果你将你的程序重定向到文件)。stdio如果您需要输出大量数据,禁用同步可能会有所帮助。如果性能是一个真正的问题(而不是将几行写入 STDOUT),只需使用printf.

Everyone thinks that they care about performance, but nobody bothers to measure it. My answer is that I/O is bottleneck anyway, no matter if you use printfor iostream. I think that printfcouldbe faster from a quick look into assembly (compiled with clang using the -O3compiler option). Assuming my error example, printfexample does way fewer calls than the coutexample. This is int mainwith printf:

每个人都认为他们关心性能,但没有人费心去衡量它。我的回答是,无论如何,I/O 都是瓶颈,无论您使用printfiostream. 我认为从快速查看程序集(使用编译器选项使用 clang编译)printf可能会更快-O3。假设我的错误示​​例,printf示例的调用次数比cout示例少。这是int mainprintf

main:                                   @ @main
@ BB#0:
        push    {lr}
        ldr     r0, .LCPI0_0
        ldr     r2, .LCPI0_1
        mov     r1, #2
        bl      printf
        mov     r0, #0
        pop     {lr}
        mov     pc, lr
        .align  2
@ BB#1:

You can easily notice that two strings, and 2(number) are pushed as printfarguments. That's about it; there is nothing else. For comparison, this is iostreamcompiled to assembly. No, there is no inlining; every single operator <<call means another call with another set of arguments.

您可以很容易地注意到两个字符串和2(number) 被作为printf参数推送。就是这样;没有别的了。为了比较,将其iostream编译为程序集。不,没有内联;每一个operator <<调用都意味着另一个带有另一组参数的调用。

main:                                   @ @main
@ BB#0:
        push    {r4, r5, lr}
        ldr     r4, .LCPI0_0
        ldr     r1, .LCPI0_1
        mov     r2, #6
        mov     r3, #0
        mov     r0, r4
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        mov     r0, r4
        mov     r1, #2
        bl      _ZNSolsEi
        ldr     r1, .LCPI0_2
        mov     r2, #2
        mov     r3, #0
        mov     r4, r0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r1, .LCPI0_3
        mov     r0, r4
        mov     r2, #14
        mov     r3, #0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r1, .LCPI0_4
        mov     r0, r4
        mov     r2, #1
        mov     r3, #0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r0, [r4]
        sub     r0, r0, #24
        ldr     r0, [r0]
        add     r0, r0, r4
        ldr     r5, [r0, #240]
        cmp     r5, #0
        beq     .LBB0_5
@ BB#1:                                 @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
        ldrb    r0, [r5, #28]
        cmp     r0, #0
        beq     .LBB0_3
@ BB#2:
        ldrb    r0, [r5, #39]
        b       .LBB0_4
.LBB0_3:
        mov     r0, r5
        bl      _ZNKSt5ctypeIcE13_M_widen_initEv
        ldr     r0, [r5]
        mov     r1, #10
        ldr     r2, [r0, #24]
        mov     r0, r5
        mov     lr, pc
        mov     pc, r2
.LBB0_4:                                @ %_ZNKSt5ctypeIcE5widenEc.exit
        lsl     r0, r0, #24
        asr     r1, r0, #24
        mov     r0, r4
        bl      _ZNSo3putEc
        bl      _ZNSo5flushEv
        mov     r0, #0
        pop     {r4, r5, lr}
        mov     pc, lr
.LBB0_5:
        bl      _ZSt16__throw_bad_castv
        .align  2
@ BB#6:

However, to be honest, this means nothing, as I/O is the bottleneck anyway. I just wanted to show that iostreamis not faster because it's "type safe". Most C implementations implement printfformats using computed goto, so the printfis as fast as it can be, even without compiler being aware of printf(not that they aren't - some compilers can optimize printfin certain cases - constant string ending with \nis usually optimized to puts).

然而,老实说,这没有任何意义,因为无论如何 I/O 都是瓶颈。我只是想表明它iostream不是更快,因为它是“类型安全的”。大多数 C 实现printf使用计算的 goto实现格式,因此printf即使编译器不知道,它也尽可能快printf(并不是说它们没有 - 有些编译器可以printf在某些情况下进行优化- 以 结尾的常量字符串\n通常被优化为puts) .

Inheritance

遗产

I don't know why you would want to inherit ostream, but I don't care. It's possible with FILEtoo.

我不知道你为什么要继承ostream,但我不在乎。也可以FILE

class MyFile : public FILE {}

Type safety

类型安全

True, variable length argument lists have no safety, but that doesn't matter, as popular C compilers can detect problems with printfformat string if you enable warnings. In fact, Clang can do that without enabling warnings.

确实,可变长度参数列表没有安全性,但这并不重要,因为printf如果启用警告,流行的 C 编译器可以检测格式字符串的问题。事实上,Clang 可以在不启用警告的情况下做到这一点。

$ cat safety.c

#include <stdio.h>

int main(void) {
    printf("String: %s\n", 42);
    return 0;
}

$ clang safety.c

safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
    printf("String: %s\n", 42);
                    ~~     ^~
                    %d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main':
safety.c:4:5: warning: format ‘%s' expects argument of type ‘char *', but argument 2 has type ‘int' [-Wformat=]
     printf("String: %s\n", 42);
     ^

回答by Mikeage

From the C++ FAQ:

C++ 常见问题解答

[15.1] Why should I use <iostream>instead of the traditional <cstdio>?

Increase type safety, reduce errors, allow extensibility, and provide inheritability.

printf()is arguably not broken, and scanf()is perhaps livable despite being error prone, however both are limited with respect to what C++ I/O can do. C++ I/O (using <<and >>) is, relative to C (using printf()and scanf()):

  • More type-safe: With <iostream>, the type of object being I/O'd is known statically by the compiler. In contrast, <cstdio>uses "%" fields to figure out the types dynamically.
  • Less error prone: With <iostream>, there are no redundant "%" tokens that have to be consistent with the actual objects being I/O'd. Removing redundancy removes a class of errors.
  • Extensible: The C++ <iostream>mechanism allows new user-defined types to be I/O'd without breaking existing code. Imagine the chaos if everyone was simultaneously adding new incompatible "%" fields to printf()and scanf()?!
  • Inheritable: The C++ <iostream>mechanism is built from real classes such as std::ostreamand std::istream. Unlike <cstdio>'s FILE*, these are real classes and hence inheritable. This means you can have other user-defined things that look and act like streams, yet that do whatever strange and wonderful things you want. You automatically get to use the zillions of lines of I/O code written by users you don't even know, and they don't need to know about your "extended stream" class.

[15.1] 为什么我要使用<iostream>而不是传统的<cstdio>

提高类型安全性、减少错误、允许可扩展性并提供可继承性。

printf()可以说没有损坏,scanf()尽管容易出错,但它可能是宜居的,但是两者都受限于 C++ I/O 可以做什么。C++ I/O(使用<<and >>)相对于 C(使用printf()and scanf()):

  • 更类型安全:使用<iostream>,编译器静态知道被 I/O 处理的对象类型。相反,<cstdio>使用“%”字段来动态确定类型。
  • 不易出错:使用<iostream>,没有多余的“%”标记必须与被 I/O 的实际对象一致。删除冗余会删除一类错误。
  • 可扩展:C++<iostream>机制允许在不破坏现有代码的情况下对新的用户定义类型进行 I/O。试想一下,如果乱每个人都在同时增加新的不兼容的“%”字段 printf()scanf()?!
  • 可继承:C++<iostream>机制是从真实的类构建的,例如std::ostreamstd::istream。与<cstdio>'s 不同FILE*,这些是真正的类,因此可以继承。这意味着您可以拥有其他用户定义的东西,它们的外观和行为都像流,但可以做任何你想做的奇怪和美妙的事情。您会自动使用由您甚至不认识的用户编写的无数行 I/O 代码,而且他们不需要知道您的“扩展流”类。

On the other hand, printfis significantly faster, which may justify using it in preference to coutin veryspecific and limited cases. Always profile first. (See, for example, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout/)

另一方面,printf明显更快,这可能证明cout非常特定和有限的情况下优先使用它是合理的。始终先配置文件。(例如,参见http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout/)

回答by Thomas

People often claim that printfis much faster. This is largely a myth. I just tested it, with the following results:

人们经常声称这printf要快得多。这在很大程度上是一个神话。我刚刚测试了一下,结果如下:

cout with only endl                     1461.310252 ms
cout with only '\n'                      343.080217 ms
printf with only '\n'                     90.295948 ms
cout with string constant and endl      1892.975381 ms
cout with string constant and '\n'       416.123446 ms
printf with string constant and '\n'     472.073070 ms
cout with some stuff and endl           3496.489748 ms
cout with some stuff and '\n'           2638.272046 ms
printf with some stuff and '\n'         2520.318314 ms

Conclusion: if you want only newlines, use printf; otherwise, coutis almost as fast, or even faster. More details can be found on my blog.

结论:如果您只想要换行符,请使用printf; 否则,cout几乎一样快,甚至更快。更多细节可以在我的博客上找到。

To be clear, I'm not trying to say that iostreams are always better than printf; I'm just trying to say that you should make an informed decision based on real data, not a wild guess based on some common, misleading assumption.

需要明确的是,我并不是想说iostreams 总是比printf; 我只是想说你应该根据真实数据做出明智的决定,而不是基于一些常见的、误导性假设的胡乱猜测。

Update: Here's the full code I used for testing. Compiled with g++without any additional options (apart from -lrtfor the timing).

更新:这是我用于测试的完整代码。编译时g++没有任何额外的选项(除了-lrt时间)。

#include <stdio.h>
#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    timespec d_start;
    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            clock_gettime(CLOCK_REALTIME, &d_start);
        }
        ~TimedSection() {
            timespec end;
            clock_gettime(CLOCK_REALTIME, &end);
            double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
            std::cerr << d_name << '\t' << std::fixed << duration << " ms\n"; 
        }
};

int main() {
    const int iters = 10000000;
    char const *text = "01234567890123456789";
    {
        TimedSection s("cout with only endl");
        for (int i = 0; i < iters; ++i)
            std::cout << std::endl;
    }
    {
        TimedSection s("cout with only '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << '\n';
    }
    {
        TimedSection s("printf with only '\n'");
        for (int i = 0; i < iters; ++i)
            printf("\n");
    }
    {
        TimedSection s("cout with string constant and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789" << std::endl;
    }
    {
        TimedSection s("cout with string constant and '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789\n";
    }
    {
        TimedSection s("printf with string constant and '\n'");
        for (int i = 0; i < iters; ++i)
            printf("01234567890123456789\n");
    }
    {
        TimedSection s("cout with some stuff and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << std::endl;
    }
    {
        TimedSection s("cout with some stuff and '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << '\n';
    }
    {
        TimedSection s("printf with some stuff and '\n'");
        for (int i = 0; i < iters; ++i)
            printf("%s01234567890123456789%i\n", text, i);
    }
}

回答by Kyle Rozendo

And I quote:

引用

In high level terms, the main differences are type safety (cstdio doesn't have it), performance (most iostreams implementations are slower than the cstdio ones) and extensibility (iostreams allows custom output targets and seamless output of user defined types).

在高级术语中,主要区别在于类型安全(cstdio 没有)、性能(大多数 iostreams 实现比 cstdio 慢)和可扩展性(iostreams 允许自定义输出目标和用户定义类型的无缝输出)。

回答by Marcelo Cantos

One is a function that prints to stdout. The other is an object that provides several member functions and overloads of operator<<that print to stdout. There are many more differences that I could enumerate, but I'm not sure what you are after.

一个是打印到标准输出的函数。另一个是提供多个成员函数和operator<<打印到标准输出的重载的对象。我可以列举出更多的差异,但我不确定您在追求什么。

回答by mishal153

For me, the real differences which would make me go for 'cout' rather than 'printf' are:

对我来说,真正让我选择 'cout' 而不是 'printf' 的区别是:

1) <<operator can be overloaded for my classes.

1) <<运算符可以为我的类重载。

2) Output stream for cout can be easily changed to a file : (: copy paste :)

2) cout 的输出流可以轻松更改为文件 :(: 复制粘贴 :)

#include <iostream>
#include <fstream>
using namespace std;

int main ()
{
    cout << "This is sent to prompt" << endl;
    ofstream file;
    file.open ("test.txt");
    streambuf* sbuf = cout.rdbuf();
    cout.rdbuf(file.rdbuf());
    cout << "This is sent to file" << endl;
    cout.rdbuf(sbuf);
    cout << "This is also sent to prompt" << endl;
    return 0;
}

3) I find cout more readable, especially when we have many parameters.

3)我发现 cout 更具可读性,尤其是当我们有很多参数时。

One problemwith coutis the formatting options. Formatting the data (precision, justificaton, etc.) in printfis easier.

一个问题cout是格式化选项。格式化数据(精度、对齐等)printf更容易。

回答by Bill Weinman

Two points not otherwise mentioned here that I find significant:

这里没有另外提到的两点我觉得很重要:

1) coutcarries a lot of baggage if you're not already using the STL. It adds over twice as much code to your object file as printf. This is also true for string, and this is the major reason I tend to use my own string library.

1)cout如果您还没有使用 STL,则需要携带很多行李。它向目标文件中添加的代码是printf. 对于 来说也是如此string,这也是我倾向于使用自己的字符串库的主要原因。

2) coutuses overloaded <<operators, which I find unfortunate. This can add confusion if you're also using the <<operator for its intended purpose (shift left). I personally don't like to overload operators for purposes tangential to their intended use.

2)cout使用重载<<运算符,我觉得这很不幸。如果您还将<<运算符用于其预期目的(左移),这可能会增加混淆。我个人不喜欢为了与其预期用途相切的目的而重载运算符。

Bottom line: I'll use cout(and string) if I'm already using the STL. Otherwise, I tend to avoid it.

底线:如果我已经在使用 STL,我将使用cout(和string)。否则,我倾向于避免它。

回答by Daniel

With primitives, it probably doesn't matter entirely which one you use. I say where it gets usefulness is when you want to output complex objects.

对于原语,您使用哪一种可能并不重要。我说当你想输出复杂的对象时它会有用处。

For example, if you have a class,

例如,如果你有一个班级,

#include <iostream>
#include <cstdlib>

using namespace std;

class Something
{
public:
        Something(int x, int y, int z) : a(x), b(y), c(z) { }
        int a;
        int b;
        int c;

        friend ostream& operator<<(ostream&, const Something&);
};

ostream& operator<<(ostream& o, const Something& s)
{
        o << s.a << ", " << s.b << ", " << s.c;
        return o;
}

int main(void)
{
        Something s(3, 2, 1);

        // output with printf
        printf("%i, %i, %i\n", s.a, s.b, s.c);

        // output with cout
        cout << s << endl;

        return 0;
}

Now the above might not seem all that great, but let's suppose you have to output this in multiple places in your code. Not only that, let's say you add a field "int d." With cout, you only have to change it in once place. However, with printf, you'd have to change it in possibly a lot of places and not only that, you have to remind yourself which ones to output.

现在上面的内容可能看起来不是那么好,但是假设您必须在代码的多个位置输出它。不仅如此,假设您添加了一个字段“int d”。使用 cout,您只需更改一次。但是,使用 printf 时,您可能需要在很多地方更改它,不仅如此,您还必须提醒自己要输出哪些地方。

With that said, with cout, you can reduce a lot of times spent with maintenance of your code and not only that if you re-use the object "Something" in a new application, you don't really have to worry about output.

话虽如此,使用 cout,您可以减少大量用于维护代码的时间,不仅如此,如果您在新应用程序中重新使用对象“Something”,您就不必担心输出。

回答by LuP

Of course you can write "something" a bit better to keep maintenance:

当然,您可以更好地编写“东西”以保持维护:

#include <iostream>
#include <cstdlib>

using namespace std;

class Something
{
    public:
        Something(int x, int y, int z) : a(x), b(y), c(z) { }
        int a;
        int b;
        int c;

        friend ostream& operator<<(ostream&, const Something&);

        void print() const { printf("%i, %i, %i\n", a, b, c); }
};

ostream& operator<<(ostream& o, const Something& s)
{
    o << s.a << ", " << s.b << ", " << s.c;
    return o;
}

int main(void)
{
    Something s(3, 2, 1);

    // Output with printf
    s.print(); // Simple as well, isn't it?

    // Output with cout
    cout << s << endl;

    return 0;
}

And a bit extended test of cout vs. printf, added a test of 'double', if anyone wants to do more testing (Visual Studio 2008, release version of the executable):

如果有人想进行更多测试(Visual Studio 2008,可执行文件的发布版本),则对 cout 与 printf 进行了一些扩展测试,添加了“双倍”测试:

#include <stdio.h>
#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    //timespec d_start;
    clock_t d_start;

    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            //clock_gettime(CLOCK_REALTIME, &d_start);
            d_start = clock();
        }
        ~TimedSection() {
            clock_t end;
            //clock_gettime(CLOCK_REALTIME, &end);
            end = clock();
            double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
                              */
                              (double) (end - d_start) / CLOCKS_PER_SEC;

            std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
        }
};


int main() {
    const int iters = 1000000;
    char const *text = "01234567890123456789";
    {
        TimedSection s("cout with only endl");
        for (int i = 0; i < iters; ++i)
            std::cout << std::endl;
    }
    {
        TimedSection s("cout with only '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << '\n';
    }
    {
        TimedSection s("printf with only '\n'");
        for (int i = 0; i < iters; ++i)
            printf("\n");
    }
    {
        TimedSection s("cout with string constant and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789" << std::endl;
    }
    {
        TimedSection s("cout with string constant and '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789\n";
    }
    {
        TimedSection s("printf with string constant and '\n'");
        for (int i = 0; i < iters; ++i)
            printf("01234567890123456789\n");
    }
    {
        TimedSection s("cout with some stuff and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << std::endl;
    }
    {
        TimedSection s("cout with some stuff and '\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << '\n';
    }
    {
        TimedSection s("printf with some stuff and '\n'");
        for (int i = 0; i < iters; ++i)
            printf("%s01234567890123456789%i\n", text, i);
    }
    {
        TimedSection s("cout with formatted double (width & precision once)");
        std::cout << std::fixed << std::scientific << std::right << std::showpoint;
        std::cout.width(8);
        for (int i = 0; i < iters; ++i)
            std::cout << text << 8.315 << i << '\n';
    }
    {
        TimedSection s("cout with formatted double (width & precision on each call)");
        std::cout << std::fixed << std::scientific << std::right << std::showpoint;

        for (int i = 0; i < iters; ++i)
            { std::cout.width(8);
              std::cout.precision(3);
              std::cout << text << 8.315 << i << '\n';
            }
    }
    {
        TimedSection s("printf with formatted double");
        for (int i = 0; i < iters; ++i)
            printf("%8.3f%i\n", 8.315, i);
    }
}

The result is:

结果是:

cout with only endl    6453.000000 ms
cout with only '\n'    125.000000 ms
printf with only '\n'    156.000000 ms
cout with string constant and endl    6937.000000 ms
cout with string constant and '\n'    1391.000000 ms
printf with string constant and '\n'    3391.000000 ms
cout with some stuff and endl    9672.000000 ms
cout with some stuff and '\n'    7296.000000 ms
printf with some stuff and '\n'    12235.000000 ms
cout with formatted double (width & precision once)    7906.000000 ms
cout with formatted double (width & precision on each call)    9141.000000 ms
printf with formatted double    3312.000000 ms

回答by Apollo

I'd like to point out that if you want to play with threads in C++, if you use coutyou can get some interesting results.

我想指出的是,如果您想在 C++ 中使用线程,如果您使用它,cout您可以获得一些有趣的结果。

Consider this code:

考虑这个代码:

#include <string>
#include <iostream>
#include <thread>

using namespace std;

void task(int taskNum, string msg) {
    for (int i = 0; i < 5; ++i) {
        cout << "#" << taskNum << ": " << msg << endl;
    }
}

int main() {
    thread t1(task, 1, "AAA");
    thread t2(task, 2, "BBB");
    t1.join();
    t2.join();
    return 0;
}

// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x

Now, the output comes all shuffled. It can yield different results too, try executing several times:

现在,输出全部打乱了。它也可以产生不同的结果,尝试执行几次:

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

You can use printfto get it right, or you can use mutex.

您可以使用printf它来正确处理,或者您可以使用mutex.

#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB

Have fun!

玩得开心!