458

printf()C++和C++有什么区别cout

4

16 回答 16

445

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

真正的差异

可扩展性

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

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

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

句法

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

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

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

虽然这看起来并不太疯狂(它只是长了两倍),但当您实际格式化参数时,事情会变得更加疯狂,而不是仅仅打印它们。例如,打印类似的东西简直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;

翻译

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

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

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

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

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

你不能打印 NUL 字节,\0

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

没人关心的差异

表现

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

每个人都认为他们关心性能,但没有人费心去衡量它。我的回答是 I/O 无论如何都是瓶颈,无论你使用printf还是iostream. 我认为通过快速查看汇编(使用编译器选项使用 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:

您可以很容易地注意到两个字符串和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:

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

遗产

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

class MyFile : public FILE {}

类型安全

诚然,可变长度参数列表没有安全性,但这没关系,因为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);
     ^
于 2013-11-27T09:23:41.020 回答
217

C++ 常见问题解答

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

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

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

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

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

于 2010-05-20T09:47:14.750 回答
47

人们经常声称这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

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

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

更新:这是我用于测试的完整代码。编译时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);
    }
}
于 2010-05-20T11:35:40.717 回答
42

引用

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

于 2010-05-20T09:45:57.417 回答
30

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

于 2010-05-20T09:46:13.063 回答
13

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

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

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

#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.

One problem with cout is the formatting options. Formatting the data (precision, justificaton, etc.) in printf is easier.

于 2010-05-20T12:01:25.697 回答
9

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

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

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

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

于 2014-12-05T21:53:56.687 回答
5

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

例如,如果你有一堂课,

#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;
}

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

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

于 2010-05-20T18:02:13.043 回答
3

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

考虑这段代码:

#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

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

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

您可以使用printf来正确处理,也可以使用mutex.

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

玩得开心!

于 2015-11-17T17:52:05.317 回答
3

我不是程序员,但我一直是人因工程师。我觉得一门编程语言应该易于学习、理解和使用,这要求它具有简单且一致的语言结构。尽管所有语言都是象征性的,因此在其核心是任意的,但有一些约定,遵循它们会使语言更容易学习和使用。

在 C++ 和其他语言中,有大量的函数被写成函数(参数),这种语法最初用于计算机时代之前的数学中的函数关系。printf()遵循这种语法,如果 C++ 的编写者想要创建任何逻辑上不同的方法来读取和写入文件,他们可以简单地使用类似的语法创建不同的函数。

在 Python 中,我们当然可以使用相当标准的object.method语法进行打印,即 variablename.print,因为变量是对象,但在 C++ 中它们不是。

我不喜欢 cout 语法,因为 << 运算符不遵循任何规则。它是一个方法或函数,即它接受一个参数并对它做一些事情。然而,它被写成好像它是一个数学比较运算符。从人为因素的角度来看,这是一种糟糕的方法。

于 2016-03-07T05:09:50.397 回答
2
cout<< "Hello";
printf("%s", "Hello"); 

两者都用于打印值。它们具有完全不同的语法。C++ 两者都有,C 只有 printf。

于 2010-05-20T09:47:03.367 回答
2

更多区别:“printf”返回一个整数值(等于打印的字符数),“cout”不返回任何内容

和。

cout << "y = " << 7;不是原子的。

printf("%s = %d", "y", 7);是原子的。

cout 执行类型检查, printf 不执行。

没有 iostream 相当于"% d"

于 2012-12-05T13:34:56.383 回答
2

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

#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;
}

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

#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);
    }
}

结果是:

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
于 2011-11-25T08:10:26.630 回答
1

我想说缺乏可扩展性printf并不完全正确:
在 C 中,这是正确的。但是在 C 中,没有真正的类。
在 C++ 中,可以重载强制转换运算符,因此,重载char*运算符并printf像这样使用:

Foo bar;
...;
printf("%s",bar);

有可能,如果 Foo 重载好的操作符。或者如果你做了一个好方法。简而言之,对我来说printf是可扩展cout的。

我可以看到的 C++ 流的技术论点(一般......不仅是 cout。)是:

  • 类型安全。(顺便说一句,如果我想打印'\n'我使用的单曲putchar('\n')……我不会用核弹杀死昆虫。)。

  • 学起来更简单。(无需学习“复杂”的参数,只需使用<<>>运算符)

  • std::string(for printfthere is std::string::c_str(), but for scanf?)一起工作

因为printf我看到:

  • 更容易,或者至少更短(就写入的字符而言)复杂的格式。对我来说更具可读性(我猜是口味问题)。

  • 更好地控制函数所做的事情(返回写入了多少字符并且有%n格式化程序:“没有打印。参数必须是指向有符号整数的指针,其中存储了到目前为止写入的字符数。”(来自printf - C++ 参考

  • 更好的调试可能性。出于与最后一个论点相同的原因。

我个人偏爱printf(和scanf)函数,主要是因为我喜欢短行,而且我不认为打印文本时的类型问题真的很难避免。我对 C 风格函数的唯一不满是它std::string不受支持。我们必须先通过 achar*才能将其交给printfstd::string::c_str()如果我们想阅读,但如何写作?)

于 2012-01-11T10:09:30.153 回答
1

TL;DR:在信任在线随机评论(包括这一评论)之前,请务必自行研究生成的机器代码大小性能可读性编码时间。

我不是专家。我刚刚无意中听到两位同事谈论由于性能问题我们应该如何避免在嵌入式系统中使用 C++。好吧,很有趣,我做了一个基于真实项目任务的基准测试。

在上述任务中,我们必须将一些配置写入 RAM。就像是:

咖啡=热
糖=无
牛奶=breast
mac=AA:BB:CC:DD:EE:FF

这是我的基准程序(是的,我知道 OP 询问了 printf(),而不是 fprintf()。尝试捕捉本质,顺便说一下,OP 的链接指向 fprintf()。)

C程序:

char coffee[10], sugar[10], milk[10];
unsigned char mac[6];

/* Initialize those things here. */

FILE * f = fopen("a.txt", "wt");

fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);

fclose(f);

C++程序:

//Everything else is identical except:

std::ofstream f("a.txt", std::ios::out);

f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
    << (int)mac[1] << ":"
    << (int)mac[2] << ":"
    << (int)mac[3] << ":"
    << (int)mac[4] << ":"
    << (int)mac[5] << endl;
f.close();

在我将它们都循环了 100,000 次之前,我已尽力打磨它们。结果如下:

C程序:

real    0m 8.01s
user    0m 2.37s
sys     0m 5.58s

C++程序:

real    0m 6.07s
user    0m 3.18s
sys     0m 2.84s

目标文件大小:

C   - 2,092 bytes
C++ - 3,272 bytes

结论:在我非常特定的平台上,使用非常特定的处理器,运行非常特定版本的Linux 内核,运行使用非常特定版本的GCC编译的程序,为了完成非常特定的任务,我会说C++ 方法更合适,因为它运行得更快,并且可读性更好。另一方面,在我看来,C 的占用空间很小,几乎没有任何意义,因为程序大小不是我们关心的问题。

记住,YMMV。

于 2017-04-01T05:08:55.560 回答
-3

printf是一个函数,而cout是一个变量。

于 2014-01-22T20:35:44.673 回答