Input and Output streams, which seem complicated but easier to use -- small talk C ++ (2)

Source: Internet
Author: User
Tags setf

[Mac 10.7.1 lion intel-based x64 gcc4.2.1 xcode4.2]

Q: What are the advantages and disadvantages of C ++'s default input and output and C?

A: Any language has its own most recommended model, because the designer may have carefully considered it. There is no need to say which one is the best, which is the very bad, the best and the very bad have restrictions. Different users can always find the most suitable method.

The input and output of C ++ is more object-oriented and modular. Its operations actually contain operations on input or output objects, whether to output an integer or a character, or a custom object. In C, I feel more like functions and procedural thinking. Output doesn't have to tell users to use an object, tell me what to output, and I will output anything to you.

Because of the object-oriented nature of C ++, you do not need to input a string like printf, but write the output variables separately; this makes it easier to write data in C ++, and sometimes it becomes more complicated to control complex output, A small format change in the format string of printf can output different situations, while using cout may require more code modification.

The objectization of C ++ and the method of overloading operators allow specific operations on the output object to be transferred to the object so that the object itself can implement specific output. printf does not have this function by default, programmers have to add specific object output logic or encapsulate a function to output object data during printf, which may make Programmers sometimes unable to remember exactly what output function is used for an object, c ++ defines the interface as <, which seems easier to use.

The printf function in C language uses a string in the dynamic parsing format to output an integer based on whether it is % d, and whether it is % C to output a character, which may cause a loss of running timeliness; the C ++ output method determines what the output is during compilation. This is a factor that may cause printf efficiency to be lower than cout.

The mixed use of C ++ and C Language Input and Output may sometimes lead to unexpected problems, mainly because the C ++ library is partly dependent on the C library. Therefore, be very careful. If you are not clear about the internal mechanism, it is best not to mix it with others.

Q: What is the relationship between classes in input and output?

A: C ++ has many designs for input and output, which jointly form a concise and easy-to-expand class design diagram that can provide input and output functions. The following is a one-to-one analysis:

For a cout object, it is an object of ostream. The definition of ostream is as follows:

  typedef basic_istream<char> istream;///< @isiosfwd  typedef basic_ostream<char> ostream;///< @isiosfwd  typedef basic_iostream<char> iostream;///< @isiosfwd

Similarly, it includes definitions of istream and iostream. For istream, ostream, and iostream, they implement specific input and output functions (of course, they also call other internal functions internally to implement final input and output ).

The implementation of the basic_istream class is as follows (partial ):

  template<typename _CharT, typename _Traits>    class basic_istream : virtual public basic_ios<_CharT, _Traits>
__istream_type&       operator>>(bool& __n)      { return _M_extract(__n); }            __istream_type&       operator>>(short& __n);            __istream_type&       operator>>(unsigned short& __n)      { return _M_extract(__n); }      __istream_type&       operator>>(int& __n);          __istream_type&       operator>>(unsigned int& __n)      { return _M_extract(__n); }      __istream_type&       operator>>(long& __n)      { return _M_extract(__n); }
     __istream_type&      get(__streambuf_type& __sb)      { return this->get(__sb, this->widen('\n')); }       int_type       peek();            __istream_type&       putback(char_type __c);

It can be seen that it implements some column operations such as inputting a variable, obtaining the final data of the input stream, and returning the data to the input stream.

The implementation of basic_ostream (partial) is as follows ):

  template<typename _CharT, typename _Traits>    class basic_ostream : virtual public basic_ios<_CharT, _Traits>
      __ostream_type&       operator<<(long __n)      { return _M_insert(__n); }            __ostream_type&       operator<<(unsigned long __n)      { return _M_insert(__n); }      __ostream_type&       operator<<(bool __n)      { return _M_insert(__n); }      __ostream_type&       operator<<(short __n);
      __ostream_type&       put(char_type __c);      __ostream_type&       flush();

It can be seen that it achieves different types of data output and refresh operations. At the same time, we can also see that they all inherit the basic_ios class. Below are some of its implementations:

  template<typename _CharT, typename _Traits>    class basic_ios : public ios_base
      void      clear(iostate __state = goodbit);      bool      good() const      { return this->rdstate() == 0; }      bool      eof() const      { return (this->rdstate() & eofbit) != 0; }      bool      fail() const      { return (this->rdstate() & (badbit | failbit)) != 0; }      bool      bad() const      { return (this->rdstate() & badbit) != 0; }

It can be seen that basic_istream and basic_ostream classes are implemented in basic_ios, where they may need to be executed together: the buffer status. Basic_ios inherits the ios_base class, and its implementation is as follows:

  class ios_base
    inline streamsize    precision() const { return _M_precision; }    inline streamsize    precision(streamsize __prec)    {      streamsize __old = _M_precision;      _M_precision = __prec;      return __old;    }    inline streamsize    width() const { return _M_width; }  inline ios_base&  boolalpha(ios_base& __base)  {    __base.setf(ios_base::boolalpha);    return __base;  }

It mainly implements precision control, width and other basic flow control.

For the iostream class, it inherits istream and ostream.

  template<typename _CharT, typename _Traits>    class basic_iostream    : public basic_istream<_CharT, _Traits>,       public basic_ostream<_CharT, _Traits>

It can be seen that it can implement all functions of istream and ostream. Also, the inheritance relationships between ifstream, ofstream, fstream, istrstream, ostrstream, strstream, and strstreambase and the above classes can be analyzed similarly.

In general, according to the final function of input and output, the implementation is abstracted from the completed part and the completed part separately, that is, the above design drawing.

Q: What exactly do istrstream, ostrstream, and strstream need to be implemented?

A: connect them with sprintf and sscanf in C. They are just operations to concatenate or retrieve a so-called string in the memory. However, C ++ has marked these classes as obsolete. classes with similar functions are stringstream, istringstream, and ostringstream. The following is an example:

Because xcode on Mac has a slight bug in stringstream processing, the following code uses gcc4.2.1 for compilation:

#include <iostream>#include <sstream>#define COUT_ENDL(str)  std::cout << #str << " is " << (str) << std::endl;int main(){    std::stringstream s;    int i = 128;    char buf[32];    int value;    s << "hello" << " " << i;    s >> buf;    s >> value;    COUT_ENDL(buf)    COUT_ENDL(value)    return 0;}

Save as stringstream. cpp, compile with G ++ stringstream. cpp-O stringstream, and run:

buf is hellovalue is 128

In fact, it is very simple to use <to store the subsequent data into the string, note that it is in string format, I is an integer still converted into string format;> extract the data, to the following variables.

Q: I think there are many forms of C ++ input and output, and some operations may be confused. Why is this happening?

A: The main reason for this problem is that C ++ uses the class concept, and input and output involve many class inheritance systems, each class may have some public functions that can be called or public variables that can be used. As a result, when the subclass is used for operations, the basic class public functions can also be used to obtain some information, this may greatly increase the number of input/output stream operations. However, no matter how many deformation methods there are, the basic functions are still those: input, output, query stream status, set stream parameters and refresh. All in all, no matter how many functions you want to encapsulate, C ++ will not block you, but the linker may block the generation of the final executable file (if the final executable file exceeds the system limit ).

Q: Why can I compile cout in the form of cout <Endl?

A: This form is similar to cout <boolalpha. See the following code:

#include <iostream>using namespace std;int main (int argc, const char * argv[]){    bool b = true;    cout << boolalpha << b << endl;    return 0;}

Based on the overload operator, the following code is also possible:

#include <iostream>using namespace std;int main (int argc, const char * argv[]){    bool b = true;    cout.operator<<(boolalpha).operator<<(b).operator<<(endl);    return 0;}

So what is boolalpha and Endl?

View the description and definition of Endl and find the following in the basic_ostream class:

  template<typename _CharT, typename _Traits>    inline basic_ostream<_CharT, _Traits>&     endl(basic_ostream<_CharT, _Traits>& __os)    { return flush(__os.put(__os.widen('\n'))); }

The description and definition of boolalpha are as follows in the ios_base class:

  inline ios_base&  boolalpha(ios_base& __base)  {    __base.setf(ios_base::boolalpha);    return __base;  }

In this case, the following code should be able to run:

#include <iostream>using namespace std;int main (int argc, const char * argv[]){    bool b = true;    boolalpha(cout);    cout << b;    endl(cout);    return 0;}

Run, consistent with the above Code. From the above we can see that boolalpha and Endl are functions, and their prototype is:

  inline ios_base&  boolalpha(ios_base& __base);
  template<typename _CharT, typename _Traits>    inline basic_ostream<_CharT, _Traits>&     endl(basic_ostream<_CharT, _Traits>& __os);

The following functions can be found in the basic_ostream class:

      __ostream_type&      operator<<(__ostream_type& (*__pf)(__ostream_type&))      {// _GLIBCXX_RESOLVE_LIB_DEFECTS// DR 60. What is a formatted input function?// The inserters for manipulators are *not* formatted output functions.return __pf(*this);      }__ostream_type&      operator<<(ios_base& (*__pf) (ios_base&))      {// _GLIBCXX_RESOLVE_LIB_DEFECTS// DR 60. What is a formatted input function?// The inserters for manipulators are *not* formatted output functions.__pf(*this);return *this;      }typedef basic_ostream<_CharT, _Traits> __ostream_type;

This is simple, cout. operator <(boolalpha) is actually calling the cout operator <(ios_base & (* _ pF) (ios_base &) function, while cout. operator <(Endl) actually calls the cout operator <(_ ostream_type & (* _ pF) (_ ostream_type &) function. Boolalpha and Endl are passed as function pointers only as parameters. Internally, boolalpha (cout); and Endl (cout); are called to implement the final function. I think one of the advantages of this design is to make users more convenient,
Use <everywhere. You don't have to worry about which function is reloaded. The upper layer has been converted internally. At the same time, for the operator, the operator is not operating on it, but the operator is operating on cout.

Q: Will cout <"\ n"; refresh the buffer?

A: For the row buffer, it will certainly refresh the buffer. Do not consider that only cout <Endl; forces the buffer to be refreshed. The following code,

#include <iostream>using namespace std;int main (int argc, const char * argv[]){    cout << "hello";    cout << "ok\n";     cout << endl;    cout << "thanks";        return 0;}

Place a breakpoint on the two cout statements and return 0; in the middle to debug and run the command:

When running to cout <"OK \ n", the above "hello" is not output, which means it is in the buffer; when running to cout <Endl, hellook \ n is output, which means \ n does cause a refresh buffer. Of course, it may also be that the buffer is too small (although it is not likely to be in the actual state), change cout <"OK \ n"; to cout <"OK "; after debugging again, hellook has no output. When running to return 0, it is found that thanks is not output. After running, thanks is output.

Of course, it is certain that \ n may not refresh the buffer, but Endl will certainly refresh the buffer.

  template<typename _CharT, typename _Traits>    inline basic_ostream<_CharT, _Traits>&     endl(basic_ostream<_CharT, _Traits>& __os)    { return flush(__os.put(__os.widen('\n'))); }

Q: cout SETF, flags, and operations such as Hex and Dec are often used. This may cause a consequence: At this time, the output stream status is not very definite, how can they be distinguished?

A: reading the source code is the most direct way to understand a problem.

The following SETF function source code:

    inline fmtflags    setf(fmtflags __fmtfl)    {      fmtflags __old = _M_flags;      _M_flags |= __fmtfl;      return __old;    }

The following flags source code:

    inline fmtflags    flags(fmtflags __fmtfl)    {      fmtflags __old = _M_flags;      _M_flags = __fmtfl;      return __old;    }

Among them, _ m_flags is a member of ios_base and stores some configuration information of the stream, such as whether to use hexadecimal output or left alignment. It can be seen that SETF only adds a configuration information to the original configuration information, while flags completely replaces the original configuration information. The combination of unsetf and SETF is also provided. The following is the stream configuration information:

  enum _Ios_Fmtflags     {       _S_boolalpha = 1L << 0,      _S_dec = 1L << 1,      _S_fixed = 1L << 2,      _S_hex = 1L << 3,      _S_internal = 1L << 4,      _S_left = 1L << 5,      _S_oct = 1L << 6,      _S_right = 1L << 7,      _S_scientific = 1L << 8,      _S_showbase = 1L << 9,      _S_showpoint = 1L << 10,      _S_showpos = 1L << 11,      _S_skipws = 1L << 12,      _S_unitbuf = 1L << 13,      _S_uppercase = 1L << 14,      _S_adjustfield = _S_left | _S_right | _S_internal,      _S_basefield = _S_dec | _S_oct | _S_hex,      _S_floatfield = _S_scientific | _S_fixed,      _S_ios_fmtflags_end = 1L << 16     };

For the hex operation, for example:

#include <iostream>using namespace std;int main (int argc, const char * argv[]){    cout.setf(ios::hex);    cout << 15 << endl;    return 0;}

Program output:

15

SETF does not enable the output stream to output in hexadecimal format. If cout

First, let's take a look at the definition of the cout

  inline ios_base&  hex(ios_base& __base)  {    __base.setf(ios_base::hex, ios_base::basefield);    return __base;  }

It can be seen that it is inconsistent with cout. SETF (IOs: Hex.

Let's take a look at the definition of The SETF function internally called by the hex function:

    inline fmtflags    setf(fmtflags __fmtfl, fmtflags __mask)    {      fmtflags __old = _M_flags;      _M_flags &= ~__mask;      _M_flags |= (__fmtfl & __mask);      return __old;    }_S_basefield = _S_dec | _S_oct | _S_hex,

Static const fmtflags basefield = _ s_basefield; you can see that _ m_flags & = ~ _ Mask is to clear all the _ s_dec, _ s_oct, _ s_hex signs in the stream state, and then add a specific sign. Cout. SETF (IOs: Hex); only adds the hexadecimal flag to the stream status, but the decimal output status in the stream status is retained, resulting in the output in decimal format.

After learning about the internal principles of the code, no matter how amazing the external phenomenon is, it seems simple.

Q: What is the difference between the clear and sync functions for input and output streams?
A: clear only indicates cleaning of the stream status flag.

      /**       *  @brief  [Re]sets the error state.       *  @param  state  The new state flag(s) to set.       *       *  See std::ios_base::iostate for the possible bit values.  Most       *  users will not need to pass an argument.      */      void      clear(iostate __state = goodbit);

The Sync or flush functions can actually refresh the buffer data.

Xichen

11:47:56

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.