說明一下,我用的是g++7.1.0編譯器,標準庫源代碼也是這個版本的。
一直以來,咱們每次使用cout輸出數據的時候,若是要換行,都知道使用形如cout << endl;
這樣的形式,那麼endl究竟是什麼呢,它是怎麼樣實現輸出一個換行符的功能的,之前我沒有思考過,但如今我想弄懂它,下面就一塊兒看一下吧。linux
在標準庫頭文件<ostream>
中,我找到了endl的操做符重載函數,以下:ios
template<typename _CharT, typename _Traits> inline basic_ostream<_CharT, _Traits>& endl(basic_ostream<_CharT, _Traits>& __os) { return flush(__os.put(__os.widen('\n'))); }
它是一個內聯的函數模板,是一個全局的函數模板,endl正是它的函數名,它的做用是往緩衝區寫入一個換行符而且當即從緩衝區刷新到外部設備中。c++
那麼endl是怎麼與<<操做符關聯起來的呢,咱們在ostream頭文件ostream類的聲明中又發現瞭如下代碼:shell
__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& (*__pf)(__ostream_type&)
類型的函數指針,這個類型與endl的類型是一致的,從而,咱們如今知道了endl的實現過程。ide
與endl一樣實現的總共是親兄弟三個,他們類型同樣,且都是對緩衝區進行操做,以下:函數
操做符 | 說明 |
---|---|
endl | 輸出一個換行符到緩衝區,且即時刷新到外部設備 |
ends | 輸出一個空字符到緩衝區 |
flush | 調用flush函數,把數據從緩衝區刷新到外部設備 |
說完endl的親兄弟,接下來講一說它的堂兄弟們,那就是格式化操做符,在某些書籍上也叫作操縱算子,操縱算子用法與endl同樣,也是形如cout << oct
這樣的形式,但它不會對緩衝區直接進行操做,它是對後續的數據輸出進行格式化,相似c語言的%d同樣,且操縱算子的實現方式與endl相似,只是<<的返回類型與參數類型不同而已,這裏就再也不多說。this
操縱算子分爲兩類,一類是無參的,定義在ios_base.h頭文件中,還有一類是有參的,定義在iomanip頭文件中。編碼
操縱算子 | 說明 |
---|---|
boolalpha | 針對bool類型變量,不是輸出0和1,而是輸出true或者false |
noboolalpha | boolalpha的反向操做 |
showbase | 在輸出八進制或者十六進制的時候,加上0x這樣的前綴,主要它要放在進制操做符的前面 |
noshowbase | showbase的反向操做 |
showpoint | 強制打印小數點 |
noshowpoint | showpoint的反向操做 |
showpos | 針對非負的數字,強制加上+號輸出 |
noshowpos | showpos的反向操做 |
skipws | 它是一個輸入類操做符,做用是在輸入時跳過空格,這一點與不使用skipws時是一致的 |
noskipws | 這裏主要是noskipws會改變>>的默認輸入方式,會把空格,製表符等也讀入 |
uppercase | 在輸出十六進制這樣的數據時,對裏面的字母進行大寫,注意它對輸出字符類型或者字符串類型是不起做用的 |
nouppercase | uppercase的反向操做 |
unitbuf | 每次輸出之後都刷新緩衝區 |
nounitbuf | unitbuf的反向操做 |
internal | 在設置了輸出寬度的狀況下,符號左對齊,值右對齊,中間使用空格填充 |
left | 在設置了輸出寬度的狀況下,輸出總體左對齊,沒有設置輸出寬度,說對齊都是耍流氓 |
right | 在設置了輸出寬度的狀況下,輸出總體右對齊,iostream流默認右對齊 |
dec | 十進制輸出,對浮點數不起效果,只對整型有效果 |
hex | 十六進制輸出,對浮點數不起效果,只對整型有效果 |
oct | 八進制輸出,對浮點數不起效果,只對整型有效果 |
fixed | 定點十進制進行輸出,默認輸出6位小數位,小數位不足補0,超出的四捨五入,保留6位 |
scientific | 科學計數法輸出 |
hexfloat | 十六進制形式輸出浮點數 |
defaultfloat | 對浮點數輸出恢復默認狀態 |
一個使用案例以下:spa
#include <iostream> using namespace std; int main() { // Initializing the integer double x = 10.2333336; //將浮點數x以十六進制形式輸出,且字母都爲大寫 cout << uppercase << hexfloat << x << endl; cout.width(12); double y = -11.222; //取消指定的浮點數格式,按默認格式輸出 cout << defaultfloat; //符號左對齊,數值右對齊,中間填充空格 cout << internal << y << endl; return 0; }
輸出結果以下:指針
0X1.47777806A1DABP+3 - 11.222
有參的操縱算子其實是在無參的基礎上實現的,是對無參操縱算子的補充,且對無參操縱算子的使用起到了簡化的做用。
首先仍是看一看有參操縱算子有哪些,以下:
操縱算子 | 參數類型 | 說明 |
---|---|---|
resetiosflags | ios_base::fmtflags,此類型是一個枚舉類型,包含了上述的無參操縱算子,多的格式之間以單豎線分隔 | 輸入輸出均可使用,重置當前流的格式 |
setiosflags | ios_base::fmtflags | 輸入輸出均可使用,增長當前流的格式 |
setbase | int | 輸入輸出均可使用,設置進制,參數值可爲8,10,16,若是是其餘值則表示使用默認的 |
setfill | 無固定類型,是一個函數模板 | 輸入輸出均可使用,設定對齊時的填充字符,雖然說是模板,但參數通常建議使用char類型 |
setprecision | int | 輸入輸出均可使用,設置精度,注意默認狀況下這裏的精度並非指小數位,而是包含整數位在內,總共能夠顯示多少位數字,可是若是事先使用fixed指定了的話,那該精度就是單指小數位了 |
setw | int | 輸入輸出均可使用,設置寬度 |
get_money | 有兩個參數,第一個參數是一個函數模板,但根據iomanip頭文件,它應該是一個long double類型或者string類型,此時該參數實際上是一個出參,輸入的數據存儲在該參數裏面,第二個參數是一個bool類型,表示是否國際化 | 輸入使用,根據設置的區域文化和編碼以及輸入的對應的貨幣表達式,獲取相應的數據 |
put_money | 有兩個參數,第一個參數是一個函數模板,但根據iomanip頭文件,它應該是一個long double類型或者string類型,第二個參數是一個bool類型,表示是否國際化 | 輸出使用,根據設置的區域文化和編碼,輸出相應的貨幣表達式 |
put_time | 第一個參數是const std::tm類型指針,第二個類型是對時間進行格式化的格式字符串 | 根據第二個參數指定格式輸出tm中數據 |
get_time | 第一個參數是const std::tm類型指針,第二個類型是對時間進行格式化的格式字符串 | 根據第二個參數指定格式把數據填充到tm中 |
帶參數的這些操做函數,前面6個實際上是比較好理解的,可是後面四個用起來就比較麻煩了,並且單獨使用也是不起做用的,下面咱們就後面四個操做符,看一下使用案例,以下:
#include <iomanip> #include <iostream> #include <time.h> #include <sstream> using namespace std; void test01() { locale loc_de = locale("en_US.utf-8"); cout.imbue(loc_de); const string str("720000000000"); cout << put_money(str) << endl; string str2; cin.imbue(loc_de); cin >> get_money(str2);//這裏要按照imbue設置的區域和編碼進行輸入,形如:72,000,000 cout << "str2=" << str2 << endl; time_t t; time(&t); tm *tmp = localtime(&t); cout << put_time(tmp, "%y %a") << endl; tm time1; istringstream iss("15:12:00 2021"); iss >> get_time(&time1, "%H:%M:%S %Y"); cout << "hour:" << time1.tm_hour << ',' << "min:" << time1.tm_min << ',' << "sec:" << time1.tm_sec << endl; } int main() { test01(); return 0; }
輸出顯示以下:
[root@mylinux ~]# ./a.out 7,200,000,000.00 12,00,00 #注意這裏是屏幕輸入的 str2=120000 21 Thu hour:15,min:12,sec:0 [root@mylinux ~]#
後面四個函數的使用就涉及到程序國際化以及區域文化的問題,好比浮點數,在咱們大中國是72000.12,那麼到了美國可能又是用72,000.12來表示,關於區域文化,這裏就不展開說明了。