'printf'与“cout”相对在 C++

发布于 2024-09-02 05:22:31 字数 221 浏览 6 评论 0 原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

榕城若虚 2024-09-09 05:22:31

如今 C+ 中引入了 std::print +23 比两者都更受欢迎,但如果您正在寻找这些旧打印方法之间的差异,我对它们进行了比较。

来源:

  • printf():C 标准库的一部分,可用于 C 和 C++。
  • cout:C++ 标准库的一部分,特定于 C++。

类型安全:

  • printf(): 依赖于格式说明符(%d 表示整数,%s 表示字符串,等)来解释数据类型。不正确的格式说明符可能会导致意外行为或崩溃。不过,您的 C 编译器很可能会捕获这些问题。
  • cout:类型安全。它自动确定输出变量的数据类型并应用适当的格式。

格式化:

  • printf():使用格式说明符和标志提供多种格式化选项。它提供了对输出呈现的更多控制。
  • cout:提供基本的格式选项,例如插入空格或换行符。与 printf 相比,对于简单输出来说,它通常不那么冗长。

面向对象的功能:

  • printf():不是为 C++ 的面向对象编程功能而设计的。
  • cout:与C++对象无缝集成,可以使用插入运算符(<<)直接输出对象。

错误处理:

  • printf():有限的错误处理功能。格式字符串中的拼写错误等问题可能要到运行时才能被发现。
  • cout:提供某种程度的错误检查。例如,尝试输出不兼容类型的数据可能会引发异常。

性能:

  • printf():由于其在 C 库中的较低级别实现,通常被认为比 cout 更快。
  • cout:由于类型检查和潜在的错误处理,可能会产生轻微的性能开销。

何时使用 Which:

  • 对于基本输出和数据类型安全,C++ 中首选 cout
  • 如果您需要更精确地控制格式或性能是一个关键问题,printf 可能是更好的选择。
  • C++23 引入了 std::print,它提供了一种具有位置参数和一些格式化功能的混合方法。

在大多数情况下,cout 提供了一种更安全、更方便的方法来处理 C++ 中的输出。 printf 提供了更多低级控制,并且在格式化或性能是主要优先事项的特定场景中可能有用。

Nowadays std::print introduced in C++23 is preferred to both, but in case you are looking for differences between those old printing methods, I included a comparison of those.

Origin:

  • printf(): Part of the C standard library, usable in both C and C++.
  • cout: Part of the C++ standard library, specific to C++.

Type Safety:

  • printf(): Relies on format specifiers (%d for integers, %s for strings, etc.) to interpret data types. Incorrect format specifiers can lead to unexpected behavior or crashes. Chances are your C compiler will catch those issues however.
  • cout: Type-safe. It automatically determines the data type of variables being output and applies the appropriate formatting.

Formatting:

  • printf(): Offers a wide range of formatting options using format specifiers and flags. It provides more control over the output presentation.
  • cout: Provides basic formatting options like inserting spaces or newlines. It's generally less verbose for simple output compared to printf.

Object-Oriented Features:

  • printf(): Not designed for object-oriented programming features of C++.
  • cout: Integrates seamlessly with C++ objects and can directly output objects using the insertion operator (<<).

Error Handling:

  • printf(): Limited error handling capabilities. Issues like typos in format strings might not be caught until runtime.
  • cout: Provides some level of error checking. For instance, attempting to output data of an incompatible type might throw an exception.

Performance:

  • printf(): Generally considered faster than cout due to its lower-level implementation in the C library.
  • cout: Might have slight performance overhead due to type checking and potential error handling.

When to Use Which:

  • For basic output and data type safety, cout is preferred in C++.
  • If you need more precise control over formatting or performance is a critical concern, printf might be a better choice.
  • C++23 introduces std::print which offers a hybrid approach with positional arguments and some formatting capabilities.

cout offers a safer and more convenient way to handle output in C++ for most cases. printf provides more low-level control and might be useful in specific scenarios where formatting or performance is a major priority.

橙幽之幻 2024-09-09 05:22:31

来自 C++ 常见问题解答

[15.1] 为什么应该使用 而不是传统的

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

printf() 可以说没有被破坏,而 scanf() 尽管容易出错,但也许还可以使用,但是两者在 C++ I/O 方面都受到限制做。 C++ I/O(使用 <<>>)是相对于 C(使用 printf() >scanf()):

  • 更加类型安全:使用 ,I/O 对象的类型为
    由编译器静态已知。在
    相比之下, 使用“%”字段
    动态地找出类型。
  • 不易出错:使用,没有冗余
    “%”标记必须一致
    与实际对象进行 I/O 操作。
    删除冗余就删除了一个类
    错误。
  • 可扩展:C++ 机制允许新的用户定义
    无需中断即可进行 I/O 的类型
    现有代码。想象一下,如果
    每个人都同时添加
    新的不兼容的“%”字段
    printf()scanf()?!
  • 可继承:C++ 机制是根据真实类构建的
    例如 std::ostream
    std::istream。与 不同
    FILE*,这些是真正的类并且
    因此可以继承。这意味着您可以
    还有其他用户定义的东西
    看起来和行为就像流一样,但
    做任何奇怪和美妙的事情
    你想要的东西。你自动
    可以使用无数行
    由您不熟悉的用户编写的 I/O 代码
    甚至知道,而且他们不需要
    了解您的“扩展流”
    类。

另一方面,printf 的速度要快得多,这可能证明在非常特定和有限的情况下优先使用它而不是 cout。始终先进行简介。 (例如,参见http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout/)

From the C++ FAQ:

[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::ostream and
    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.

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

渡你暖光 2024-09-09 05:22:31

人们经常声称 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 几乎同样快,甚至更快。更多详细信息可以在我的博客上找到。

需要明确的是,我并不是想说 iostream 总是比 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);
    }
}

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

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, cout is almost as fast, or even faster. More details can be found on my blog.

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.

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

#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);
    }
}
失退 2024-09-09 05:22:31

引用

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

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

蓝戈者 2024-09-09 05:22:31

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

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.

阿楠 2024-09-09 05:22:31

对我来说,让我选择“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 中格式化数据(精度、合理性等)更容易。

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.

ゞ花落谁相伴 2024-09-09 05:22:31

我发现这里没有另外提及的两点很重要:

1) 如果您尚未使用 STL,则 cout 会带来很多负担。它向目标文件添加的代码是 printf 的两倍多。对于 string 也是如此,这是我倾向于使用自己的字符串库的主要原因。

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

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

Two points not otherwise mentioned here that I find significant:

1) cout carries 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.

2) cout uses 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.

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

我不吻晚风 2024-09-09 05:22:31

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

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

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

我不喜欢 cout 语法,因为 <<运营商不遵守任何规则。它是一个方法或函数,即它接受一个参数并对其执行某些操作。然而,它的编写方式就好像它是一个数学比较运算符。从人为因素的角度来看,这是一个糟糕的方法。

I'm not a programmer, but I have been a human factors engineer. I feel a programming language should be easy to learn, understand and use, and this requires that it have a simple and consistent linguistic structure. Although all the languages is symbolic and thus, at its core, arbitrary, there are conventions and following them makes the language easier to learn and use.

There are a vast number of functions in C++ and other languages written as function(parameter), a syntax that was originally used for functional relationships in mathematics in the pre-computer era. printf() follows this syntax and if the writers of C++ wanted to create any logically different method for reading and writing files they could have simply created a different function using a similar syntax.

In Python we of course can print using the also fairly standard object.method syntax, i.e. variablename.print, since variables are objects, but in C++ they are not.

I'm not fond of the cout syntax because the << operator does not follow any rules. It is a method or function, i.e. it takes a parameter and does something to it. However it is written as though it were a mathematical comparison operator. This is a poor approach from a human factors standpoint.

愿与i 2024-09-09 05:22:31

更新 2023:

从 c++23 打印到控制台的惯用方法应该是使用 std::print (或 std::println 添加换行符),它在格式字符串语法中使用 {} 占位符(见下文):

#include <print>

int main()
{
    std::println("{}, {} !", "Hello", "world");
}

但是目前,编译器对它的支持很差。

同时我们可以使用 {fmt} 库来实现类似的 API。
请注意,C++ 标准实际上(大部分)基于 {fmt} 的子集。
在这里查看更多相关信息: libfmt 和 std:: 之间有什么区别格式?
有关格式字符串语法的详细信息,请参阅此处:{fmt} 格式字符串语法

工作示例:

#include <fmt/core.h>

int main()
{
    fmt::println("{}, {} !", "Hello", "world");
}

现场演示 - Godbolt


更新 2024:

当前的 gcc (14.1 )和 clang (18.1) 最终支持使用 标头,因此上面的第一个代码片段可以按预期编译和运行:

现场演示 - Godbolt

Update 2023:

The idiomatic way to print to the console from c++23 is supposed to be with std::print (or std::println to add a newline), which uses {} placeholders in the format string syntax (see below):

#include <print>

int main()
{
    std::println("{}, {} !", "Hello", "world");
}

However as of now, the compilers support for it is very poor.

Meanwhile we can use the {fmt} library for a similar API.
Note that the c++ standard is actually based (mostly) on a subset of {fmt}.
See more about it here: What are the differences between libfmt and std::format?.
For more info about the format string syntax see here: {fmt} Format String Syntax.

Working example:

#include <fmt/core.h>

int main()
{
    fmt::println("{}, {} !", "Hello", "world");
}

Live demo - Godbolt


Update 2024:

The current gcc (14.1) and clang (18.1) finally supports using the <print> header so the first code snippet above compiles and runs as expected:

Live demo - Godbolt

橘虞初梦 2024-09-09 05:22:31

API

printf 使用基于替换的 API,其中以 % 开头的占位符替换为格式化参数:

printf("The answer is %d.\n", answer);

cout 或者,更一般地说,ostream 使用基于串联的 API,其中部分格式化消息与参数交错:

std::cout << "The answer is " << answer << ".\n";

具有适当同步的基于替换的 API 提供原子性,例如,当从多个线程写入时,用 printf 写入的不同消息不会交错,而用 cout 写入的部分消息可能会交错。为此,C++20 引入了 std::osyncstream< /a> 这是实现原子性的笨拙方法。

使用运算符重载格式化很快就会变得很麻烦,例如

std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";

FastFormat

printf("%.2f\n", 1.23456);

的作者 Matthew Wilson 称之为 “V 字形地狱”

可扩展性

cout 通过重载运算符<< 支持用户定义类型的格式化。尽管有 printf 执行相同操作。 html" rel="nofollow noreferrer">glibc 扩展 在实践中很少使用。

安全

printf 使用本质上不安全的可变参数,除非您使用类似 GCC 的 format 属性 仅适用于文字格式字符串。用户有责任通过格式说明符正确传递类型信息。任何不匹配都会导致未定义的行为,并且是常见的漏洞来源

cout/ostreams 是类型安全的,用户不需要手动处理类型信息。

缓冲

cout 添加另一层缓冲并默认与底层 C 流同步。这带来了显着的性能开销。禁用此同步是可能的,但代价是与 C 和其他语言的互操作性较差。

格式化状态

printf 中,格式化是通过格式字符串控制的,并与流本身分离。在 cout/ostreams 中,格式化状态存储在流中,这可能会对性能产生负面影响并导致意外结果。引用 N4412:iostream 的缺点

格式化参数(例如大写/小写和基数)通过设置标志来指定,这些标志通常会持续任意数量的后续低级格式化操作,直到显式更改为止。这种方法禁止编译时检查和编译时格式选择,并可能建立线程之间共享的状态(这需要同步才能访问)。

语言环境

printf 使用全局 C 语言环境。

cout 使用与流关联的 C++ 区域设置。

printfcout 默认情况下都使用语言环境。

性能

由于上述原因,cout 通常比 printf 慢:额外的缓冲和同步(可以禁用)以及有状态 API。

语言

printf是C标准库的一部分,可以在C和C++中使用。 cout是C++标准库的一部分,只能在C++中使用。


使用 C++23 std:: 可以两全其美打印。它提供了带有位置参数的基于替换的 API。它是可扩展的、类型安全的,不会引入额外的缓冲,并使本地化格式成为一种选择。

免责声明:我是 C++23 std::print 的作者。

API

printf uses a replacement-based API with placeholders starting with % replaced with formatted arguments:

printf("The answer is %d.\n", answer);

cout or, more generally, ostreams use a concatenation-based API with parts of a formatted message interleaved with arguments:

std::cout << "The answer is " << answer << ".\n";

A replacement-based API with proper synchronization provides atomicity, e.g. when writing from multiple threads different messages written with printf won't interleave while parts of the messages written with cout may interleave. For this reason C++20 introduced std::osyncstream which is a clunky way of achieving atomicity.

With operator overloading formatting can quickly become cumbersome, e.g.

std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";

vs

printf("%.2f\n", 1.23456);

Matthew Wilson, the author of FastFormat, called this "chevron hell".

Extensibility

cout supports formatting of user-defined types through overloading of operator<<. There is no standard way to do the same with printf, although there is a glibc extension which is rarely used in practice.

Safety

printf uses varargs which are inherently unsafe unless you use something like GCC's format attribute which only works with literal format strings. It is a user's responsibility to correctly pass type information via format specifiers. Any mismatch results in an undefined behavior and is a common source of vulnerabilities.

cout/ostreams are type-safe and the user doesn't need to manually handle type information.

Buffering

cout adds another layer of buffering and synchronizes with the underlying C streams by default. This brings significant performance overhead. It is possible to disable this synchronization at the cost of worse interoperability with C and potentially other languages.

Formatting state

In printf formatting is controlled via a format string and decoupled from the stream itself. In cout/ostreams the formatting state is stored in the stream which may negatively affect performance and cause unexpected results. Quoting N4412: Shortcomings of iostreams:

Formatting parameters (such as uppercase/lowercase and radix) are specified by setting flags, which mostly persist for an arbitrary number of subsequent low-level formatting operations, until explicitly changed. This approach inhibits compile-time checks and compile-time choice of formatting, and potentially establishes state shared between threads (which requires synchronization for access).

Locales

printf uses the global C locale.

cout uses the C++ locale associated with the stream.

Both printf and cout use locales by default.

Performance

cout is often slower than printf for reasons mentioned above: extra buffering and synchronization (can be disabled) and stateful API.

Language

printf is a part of the C standard library and can be used in C and C++. cout is a part of the C++ standard library and can only be used in C++.


You can have the best of both worlds by using C++23 std::print. It provides a replacement-based API with positional arguments. It is extensible, type-safe, doesn't introduce extra buffering and makes localized formatting an opt-in.

Disclaimer: I'm the author of C++23 std::print.

拥抱没勇气 2024-09-09 05:22:31

我想指出的是,如果您想在 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

玩得开心!

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

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 printf to get it right, or you can use mutex.

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

Have fun!

请你别敷衍 2024-09-09 05:22:31

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

例如,如果您有一个类,

#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”,您实际上不必担心输出。

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.

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.

倒数 2024-09-09 05:22:31
cout<< "Hello";
printf("%s", "Hello"); 

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

cout<< "Hello";
printf("%s", "Hello"); 

Both are used to print values. They have completely different syntax. C++ has both, C
only has printf.

腹黑女流氓 2024-09-09 05:22:31

当然,您可以写一些更好的“东西”来保持维护:

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

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):

#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
╄→承喏 2024-09-09 05:22:31

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

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

可能的:如果 Foo 重载了 good 运算符。或者如果你有一个好的方法。简而言之,对我来说,printfcout 一样可扩展。

我可以看到的 C++ 流的技术参数(一般来说......不仅仅是 cout。)是:

  • 类型安全。 (顺便说一句,如果我想打印一个 '\n' 我使用 putchar('\n')...我不会使用核武器-用炸弹杀死昆虫。)。

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

  • std::string 本地工作 (对于 printfstd::string::c_str(),但是对于 scanf?)

对于 printf 我看到:

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

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

  • 更好的调试可能性。

我个人偏好使用 printf (和 scanf<)。 /code>) 函数,主要是因为我喜欢短行,而且我认为打印文本时的类型问题确实很难避免。
我对 C 风格函数的唯一不满是不支持 std::string。在将其交给 printf 之前,我们必须先检查 char* (如果我们想要的话,可以使用 std::string::c_str()读了,但是怎么写呢?)

I would like say that extensibility lack of printf is not entirely true:
In C, it is true. But in C, there are no real classes.
In C++, it is possible to overload cast operator, so, overloading a char* operator and using printf like this:

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

can be possible, if Foo overload the good operator. Or if you made a good method. In short, printf is as extensible as cout for me.

Technical argument I can see for C++ streams (in general... not only cout.) are:

  • Typesafety. (And, by the way, if I want to print a single '\n' I use putchar('\n')... I will not use a nuke-bomb to kill an insect.).

  • Simpler to learn. (no "complicated" parameters to learn, just to use << and >> operators)

  • Work natively with std::string (for printf there is std::string::c_str(), but for scanf?)

For printf I see:

  • Easier, or at least shorter (in term of characters written) complex formatting. Far more readable, for me (matter of taste I guess).

  • Better control of what the function made (Return how many characters where written and there is the %n formatter: "Nothing printed. The argument must be a pointer to a signed int, where the number of characters written so far is stored." (from printf - C++ Reference)

  • Better debugging possibilities. For same reason as last argument.

My personal preferences go to printf (and scanf) functions, mainly because I love short lines, and because I don't think type problems on printing text are really hard to avoid.
The only thing I deplore with C-style functions is that std::string is not supported. We have to go through a char* before giving it to printf (with the std::string::c_str() if we want to read, but how to write?)

来世叙缘 2024-09-09 05:22:31

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

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

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

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

没有相当于 "% d" 的 iostream

More differences:
"printf" returns an integer value (equal to the number of characters printed) and "cout" does not return anything

And.

cout << "y = " << 7; is not atomic.

printf("%s = %d", "y", 7); is atomic.

cout performs typechecking, printf doesn't.

There's no iostream equivalent of "% d"

始于初秋 2024-09-09 05:22:31

TL;DR:始终对生成的机器代码大小性能可读性编码时间进行自己的研究在相信网上的随机评论之前,包括这个。

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

在上述任务中,我们必须将一些配置写入 RAM。像这样的东西:

咖啡=热
糖=无
牛奶=母乳
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

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

记住,YMMV。

TL;DR: Always do your own research, in regard of generated machine code size, performance, readability and coding time before trusting random comments online, including this one.

I'm no expert. I just happened to overhear two co-workers talking about how we should avoid using C++ in embedded systems because of performance issues. Well, interesting enough, I did a benchmark based on a real project task.

In said task, we had to write some config to RAM. Something like:

coffee=hot
sugar=none
milk=breast
mac=AA:BB:CC:DD:EE:FF

Here's my benchmark programs (Yes, I know OP asked about printf(), not fprintf(). Try to capture the essence and by the way, OP's link points to fprintf() anyway.)

C program:

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++ program:

//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();

I did my best to polish them before I looped them both 100,000 times. Here are the results:

C program:

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

C++ program:

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

Object file size:

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

Conclusion: On my very specific platform, with a very specific processor, running a very specific version of Linux kernel, to run a program which is compiled with a very specific version of GCC, in order to accomplish a very specific task, I would say the C++ approach is more suitable because it runs significantly faster and provide much better readability. On the other hand, C offers small footprint, in my opinion, means nearly nothing because program size is not of our concern.

Remeber, YMMV.

煮酒 2024-09-09 05:22:31

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

printf is a function whereas cout is a variable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文