首頁歷史 > 正文

std::cin、std::cout、std::cerr和std::endl在C++裡的真實面目

2022-03-18由 牛頓學計算機 發表于 歷史

C++輸入和輸出

在C++裡std::cin、std::cout、std::cerr和std::endl分別是標準輸入、標準輸出、標準錯誤輸出和重新整理緩衝區並換行,它們都在名稱空間std中,那麼它們真實面目是什麼?我們先來看一段程式碼:

#include int main(){std::cout << “Hello World!” << std::endl;std::cerr << “error” << std::endl;return 0;}

這段程式碼很簡單,就是輸出“Hello world!”和“error”,那麼這段程式碼的底層原理是?我們先來看一下std::cout在標準庫中的定義:

#ifndef _LIBCPP_HAS_NO_STDOUTextern _LIBCPP_FUNC_VIS ostream cout;extern _LIBCPP_FUNC_VIS wostream wcout;#endif……typedef basic_streambuf streambuf;typedef basic_istream istream;typedef basic_ostream ostream;typedef basic_iostream iostream;……template class _LIBCPP_TEMPLATE_VIS basic_ostream: virtual public basic_ios<_CharT, _Traits>{ …… };

從以上程式碼我們可以看出std::cout是一個類basic_stream的一個例項,那麼很容易我們就能想到<<很有可能是類basic_stream的一個成員函式,繼續追蹤下去,看看<<到底是啥。在類模板basic_stream中我們找到成員函式宣告如下:

basic_ostream& operator<<(bool __n);basic_ostream& operator<<(short __n);basic_ostream& operator<<(unsigned short __n);basic_ostream& operator<<(int __n);basic_ostream& operator<<(unsigned int __n);basic_ostream& operator<<(long __n);basic_ostream& operator<<(unsigned long __n);basic_ostream& operator<<(long long __n);basic_ostream& operator<<(unsigned long long __n);basic_ostream& operator<<(float __f);basic_ostream& operator<<(double __f);basic_ostream& operator<<(long double __f);basic_ostream& operator<<(const void* __p);basic_ostream& operator<<(basic_streambuf* __sb);

充分證實了我們猜想,<<其實是成員函式operator<<並且返回值是basic_ostream&,到這裡我們就可以看出std::cout << “Hello World!”其實是basic_ostream例項變數cout呼叫成員函式operator<<輸出字串“Hello World!”並返回basic_ostream&。

那麼std::endl是不是某個類的例項呢?我們看看std::endl在標準庫的定義:

template inline _LIBCPP_INLINE_VISIBILITYbasic_ostream<_CharT, _Traits>&endl(basic_ostream<_CharT, _Traits>& __os){__os。put(__os。widen(‘\n’));__os。flush();return __os;}

從程式碼裡可以看出,std::endl其實是一個函式模板,呼叫該函式會將一個換行符“\n”放入緩衝區,並重新整理緩衝區,最後返回basic_ostream&。到這裡我們終於明白std::cout << “Hello World!” << std::endl;的含義了,basic_ostream例項變數cout呼叫成員函式operator<<輸出字串“Hello World!”,返回basic_ostream&並繼續呼叫成員函式operator<<輸出換行符並重新整理輸出緩衝區。

現在我們很容易想到std::cerr和std::cout應該差不多,區別則是std::cerr是標準錯誤輸出,將資訊輸出到標準錯誤流。std::cerr定義如下:

extern _LIBCPP_FUNC_VIS ostream cerr;extern _LIBCPP_FUNC_VIS wostream wcerr;extern _LIBCPP_FUNC_VIS ostream clog;extern _LIBCPP_FUNC_VIS wostream wclog;

最後我們看看std::cin到底是什麼玩意,先來看下下面這段程式碼:

#include int main(){std::string name;std::cin >> name;return 0;}

程式碼很簡單,就是想透過標準輸入輸入名字,並儲存在變數name中。有了上面的經驗,我們很容易想到std::cin應該是某個類的例項變數,而>>則是類的成員函式。std::cin的定義如下:

#ifndef _LIBCPP_HAS_NO_STDINextern _LIBCPP_FUNC_VIS istream cin;extern _LIBCPP_FUNC_VIS wistream wcin;#endif……typedef basic_streambuf streambuf;typedef basic_istream istream;typedef basic_ostream ostream;typedef basic_iostream iostream;……template class _LIBCPP_TEMPLATE_VIS basic_istream: virtual public basic_ios<_CharT, _Traits>{ …… };

從程式碼中可以看出std::cin是類basic_istream的例項變數,且basic_istream是類模板。下面我們看看>>在basic_istream中宣告:

basic_istream& operator>>(basic_streambuf* __sb);basic_istream& operator>>(bool& __n);basic_istream& operator>>(short& __n);basic_istream& operator>>(unsigned short& __n);basic_istream& operator>>(int& __n);basic_istream& operator>>(unsigned int& __n);basic_istream& operator>>(long& __n);basic_istream& operator>>(unsigned long& __n);basic_istream& operator>>(long long& __n);basic_istream& operator>>(unsigned long long& __n);basic_istream& operator>>(float& __f);basic_istream& operator>>(double& __f);basic_istream& operator>>(long double& __f);basic_istream& operator>>(void*& __p);

不出我們所料>>確實是成員函式operator>>並返回basic_istream&,那麼這段程式碼std::cin>>name就很容易理解了,basic_istream類例項變數cin呼叫成員函式operator>>從標準輸入輸入資料,並儲存在變數name中。

到這裡std::cout、std::cin、std::cerr和std::endl的含義終於真相大白了!

往期推薦

C++11很吊的新特性!std::function

C++裡std::enable_shared_from_this是幹什麼用的?

C++ mutable關鍵字如何使用?

頂部