当我们使用printf然后我们使用格式说明符(例如%c,%p)但是当我们使用cout时我们不使用它们为什么以及在后台做什么因为我们没有使用它们?
我知道它们在c和c ++中的使用方式不同,但我仍然想知道如何在cout中进行格式化,而在printf中通过格式说明符完成。
答案 0 :(得分:3)
在C ++中,ostream::operator<<
因不同类型而被重载。您可以尝试挖掘标准库实现,以确切了解它的外观,但它将归结为大致相当于以下内容:
class ostream
{
public:
ostream& operator<<( int val );
ostream& operator<<( float val );
ostream& operator<<( const char* val );
};
真正的实现将比上面复杂得多,但这大致是一个想法。希望这个实现比printf更有效,因为编译器可以在适当的时候更容易地内联代码。请考虑以下事项:
int val = 0;
printf("%d\n", val);
std::cout << val << std::endl;
在printf的情况下,一个天真编译的程序(由编译器编译而不知道格式说明符的程序)将不得不在运行时解析“%d \ n”。与std :: cout调用相比,在这种情况下,编译器只需要确定要使用哪个重载,然后可以内联代码。
也就是说,c标准中没有任何内容表明编译器在编译时无法解析格式说明符(如果可用)。实际上,使用格式说明符和c ++ ostreams的c样式日志记录库之间的性能差异是...... nuanced。
答案 1 :(得分:2)
因为printf
设计得当且cout
内部状态令人讨厌。使用printf
,您希望每个参数格式化的方式在格式字符串中是显式的;没有隐藏的状态。使用cout
,您还可以控制格式(字段宽度等内容),但它是iostream对象中的隐藏状态。如果流的前一个用户将其保留为非默认状态,除非您明确重置状态,否则您将做错事。你甚至不想考虑多线程使用案例中发生的事情......
答案 2 :(得分:0)
基本上答案是运营商重载。只要函数采用不同的参数,函数就可以具有相同的名称。 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。