3

When we use printf then we use format specifiers (such as %c,%p) but when we use cout we don't use them why and what is being done in background because which we are not using them ?

I know they are used in differently in c and c++ but still i want to know how formatting is being done in cout, while it is done in printf through format specifiers.

  • 2
    Are you unaware of stream modifiers or asking how they work? – Duck Sep 24 '13 at 04:41
  • 1
    Or rather how they fail to work... – R.. GitHub STOP HELPING ICE Sep 24 '13 at 04:50
  • 1
    @Duck yes i am unaware of stream modifiers and how they work –  Sep 24 '13 at 05:01
  • One huge problem of cout is the hardened possibility to make it easy to translate. The printf() function at least supports positional arguments, which makes it possible, only it does not work very well across platforms. Another type of approach to this problem is seen in the arg() function of the Qt string called QString. http://qt-project.org/doc/qt-5.1/qtcore/qstring.html#arg In this case you use %1, %2, %3... to reference the first, second and third arg(). This means you can write "the %1 car" in English and "la voiture %1" in French (i.e. replace %1 with a colour.) Go do that with cout! – Alexis Wilke Sep 24 '13 at 05:13

3 Answers3

4

In C++ the ostream::operator<< is overloaded for different types. You can try and dig through your standard library implementation to see exactly what it looks like, but it will boil down to something that is approximately equivalent to the following:

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

A real implementation will be much more complicated than the above, but that is roughly the idea. The hope was that this implementation would be more efficient than printf because the compiler could more easily inline code when appropriate. Consider the following:

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

In the case of the printf a naively compiled program (one compiled by a compiler with no knowledge of format specifiers) would have to do the parsing of "%d\n" at runtime. Contrast that with the std::cout call, in which case the compiler merely needs to figure out which overload to use, and can then inline the code.

That said, there is nothing in the c standard that says a compiler can't parse the format specifiers at compile time if they are available. In practice the performance difference between a c style logging library using format specifiers and c++ ostreams is... nuanced.

Community
  • 1
  • 1
Dan O
  • 4,323
  • 5
  • 29
  • 44
4

Because printf is properly designed and cout has nasty internal state. With printf, the way you want each argument formatted is explicit in the format string; there is no hidden state. With cout, you can also control formatting (things like field width, etc.), but it's a hidden state inside the iostream object. If the previous user of the stream has left it in a non-default state, you'll do the wrong thing unless you explicitly reset the state. You don't even want to think about what happens in multi-threaded usage cases...

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • I wouldn't call printf properly designed either. It has no type safety, is implemented with the dangerous va_list feature and does silent, implicit promotions on its arguments. So I would perhaps call printf as far from properly designed as a C function goes. And then C++ adds the necessary means to design an even worse console printing function... – Lundin Sep 24 '13 at 06:42
  • To the extent iostreams have "hidden" state, printf and company do as well (though admittedly quite a bit less). Just for one example, try to contemplate how you'd implement the `%n` "conversion" without internal state. Though it's shorter term, conversion modifiers like the width, precision, `-`, `+`, and `#` also affect hidden internal state. – Jerry Coffin Sep 24 '13 at 06:43
  • 2
    No, the state related to `%n` is state of the *current call* to `printf` (automatic storage), not state of the `FILE`. There is no state related to `printf` formatting as part of the `FILE` or global storage (aside from nonstandard glibc-specific registration of additional format functions, and perhaps similar things on other implementations, which are in the realm of UB). – R.. GitHub STOP HELPING ICE Sep 24 '13 at 07:06
0

Basically the answer is operator overloading. Functions can have the same name as long as they take different parameters. operator<< is the function name you're wondering about. The compiler knows the type of what you're trying to print out, and calls the correct operator<<.

This is why if you create your own object you can't just write std::cout << yourObject; and expect it to work how you'd probably like it to. You have to specify how it should be printed,

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

But, happily, that's already been done for you behind the scenes in the case of something like an int. See: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 for a full list of provided overloads.

Adam Burry
  • 1,904
  • 13
  • 20
Memento Mori
  • 3,327
  • 2
  • 22
  • 29