printf()和cout在c++中的区别是什么?


当前回答

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

1) <<操作符可以为我的类重载。

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)我发现cout更具可读性,特别是当我们有很多参数时。

cout的一个问题是格式化选项。在printf中格式化数据(精度,合理性等)更容易。

其他回答

人们经常声称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);
    }
}

我引用一下:

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

当然,你可以把“something”写得更好一点,以保持维护:

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

还有一个cout vs. printf的扩展测试,如果有人想做更多的测试,添加了一个'double'的测试(Visual Studio 2008,可执行文件的发布版本):

#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

一个是输出到标准输出的函数。另一个是一个对象,它提供了几个成员函数和输出到stdout的操作符<<的重载。我可以列举更多的不同之处,但我不确定你想要的是什么。

我想指出的是,如果你想在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,也可以使用互斥。

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

玩得开心!