为什么我们不将格式说明符与 cout 一起使用?

Why we don't use format specifiers with cout?

本文关键字:一起 cout 说明符 我们 格式 为什么      更新时间:2023-10-16

当我们使用 printf 时,我们使用格式说明符(例如 %c,%p(,但是当我们使用 cout 时,我们不使用它们为什么以及在后台做什么,因为我们没有使用它们?

我知道它们在 c 和 c++ 中的使用方式不同,但我仍然想知道格式化是如何在 cout 中完成的,而它是在 printf 中通过格式说明符完成的。

在C++中,ostream::operator<<对于不同的类型是重载的。您可以尝试挖掘标准库实现以准确查看它的外观,但它将归结为大致等效于以下内容的内容:

class ostream
{
public:
   ostream& operator<<( int val );
   ostream& operator<<( float val );
   ostream& operator<<( const char* val );
};

真正的实现将比上述复杂得多,但大致就是这个想法。希望这种实现比printf更有效,因为编译器可以在适当的时候更容易地内联代码。请考虑以下事项:

int val = 0;
printf("%dn", val);
std::cout << val << std::endl;

在 printf 的情况下,一个天真编译的程序(由不了解格式说明符的编译器编译的程序(必须在运行时解析 "%d"。与 std::cout 调用形成对比,在这种情况下,编译器只需要确定要使用的重载,然后就可以内联代码。

也就是说,c 标准中没有任何内容说编译器无法在编译时解析格式说明符(如果它们可用(。实际上,使用格式说明符和 c++ ostream 的 c 样式日志记录库之间的性能差异是......细致 入微。

因为printf设计正确,cout内部状态令人讨厌。使用 printf ,您希望每个参数格式化的方式在格式字符串中是明确的;没有隐藏状态。使用 cout ,您还可以控制格式(如字段宽度等(,但它是 iostream 对象中的隐藏状态。如果流的上一个用户将其保留为非默认状态,则除非显式重置状态,否则您将执行错误的操作。您甚至不想考虑在多线程用例中会发生什么......

基本上答案是运算符重载。函数可以具有相同的名称,只要它们采用不同的参数。 operator<<是您想知道的函数名称。编译器知道您尝试打印的内容的类型,并调用正确的operator<<

这就是为什么如果你创建自己的对象,你不能只写std::cout << yourObject;并期望它按照你想要的方式工作。您必须指定应如何打印,

ostream& operator<<(ostream& os, const YourObject& rhs) {
  os << rhs.member;
  return os;
}

但是,令人高兴的是,在像int这样的情况下,这已经在幕后为您完成了。请参阅:http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 以获取提供的重载的完整列表。