C++ stream格式化輸出輸入

本文摘自C++primer第四版附錄A3

A.3.3. 控制輸出格式

許多操縱符使我們能夠改變輸出的外觀。有兩大類的輸出控制:控制數值的表示,以及控制填充符的數量和佈局。

控制布爾值和格式

改變對象格式化狀態的操縱符的一個例子是 boolalpha 操縱符。默認情況下,將 bool 值顯示爲 1 或 0,true 值顯示爲 1,而 false值顯示爲 0。可以通過流的 boolalpha 操縱符覆蓋這個格式化:

cout << "default bool values: "
          << true << " " << false
          << "\nalpha bool values: "
          << boolalpha
          << true << " " << false
          << endl;

執行時,這段程序產生下面的輸出:

default bool values: 1 0
     alpha bool values: true false


一旦將 boolalpha “寫”至 cout,從這個點起就改變了 cout 將怎樣顯示 bool 值,後續顯示 bool 值的操作將用 true 或 false 進行顯示。

要取消 cout 的格式狀態改變,必須應用 noboolalpha

bool bool_val;
cout << boolalpha    // sets internal state of cout
     << bool_val
     << noboolalpha; // resets internal state to default formatting


現在只改變 bool 值的格式化來顯示 bool_val,並且立即將流重置爲原來的狀態。

指定整型值的基數

默認情況下,用十進制讀寫整型值。通過使用操縱符 hexoct 和 dec,程序員可以將表示進制改爲八進制、十六進制或恢復十進制(浮點值的表示不受影響):

const int ival = 15, jval = 1024; // const, so values never change
     cout << "default: ival = " << ival
          << " jval = " << jval << endl;
     cout << "printed in octal: ival = " << oct << ival
          << " jval = " << jval << endl;
     cout << "printed in hexadecimal: ival = " << hex << ival
          << " jval = " << jval << endl;
     cout << "printed in decimal: ival = " << dec << ival
          << " jval = " << jval << endl;


編譯和執行的時候,程序產生下面的輸出:

default: ival = 15 jval = 1024
     printed in octal: ival = 17 jval = 2000
     printed in hexadecimal: ival = f jval = 400
     printed in decimal: ival = 15 jval = 1024


注意,像 boolalpha 一樣,這些操縱符改變格式狀態。它們影響緊接在後面的輸出,以及所有後續的整型輸出,直到通過調用另一操縱符重圍格式爲止。

指出輸出的基數

默認情況下,顯示數值的時候,不存在關於所用基數的可見記號。例如,20 是 20,還是 16 的八進制表示?按十進制模式顯示數值的時候,會按我們期待的格式打印數值。如果需要打印八進制或十六進制值,可能應該也使用 showbase 操縱符。showbase 操縱符導致輸出流使用的約定,與指定整型常量基數所用的相同:

  • 以 0x 爲前導表示十六進制。

  • 以 0 爲前導表示八進制。

  • 沒有任何前導表示十進制。

修改程序使用 showbase 如下:

const int ival = 15, jval = 1024; // const so values never change
     cout << showbase; // show base when printing integral values
     cout << "default: ival = " << ival
          << " jval = " << jval << endl;
     cout << "printed in octal: ival = " << oct << ival
          << " jval = " << jval << endl;
     cout << "printed in hexadecimal: ival = " << hex << ival
          << " jval = " << jval << endl;
     cout << "printed in decimal: ival = " << dec << ival
          << " jval = " << jval << endl;
     cout << noshowbase; // reset state of the stream


修改後的輸出使得基礎值到底是什麼很清楚:

default: ival = 15 jval = 1024
     printed in octal: ival = 017 jval = 02000
     printed in hexadecimal: ival = 0xf jval = 0x400
     printed in decimal: ival = 15 jval = 1024


noshowbase 操縱符重置 cout,以便它不再顯示整型值的表示基數。

默認情況下,十六進制值用帶小寫 x 的小寫形式打印。可以應用 uppercase 操縱符顯示 X 並將十六進制數字 a - f 顯示爲大寫字母。

cout << uppercase << showbase << hex
          << "printed in hexadecimal: ival = " << ival
          << " jval = " << jval << endl
          << nouppercase << endl;


前面的程序產生下面的輸出:

printed in hexadecimal: ival = 0XF jval = 0X400

要恢復小寫,就應用 nouppercase 操縱符。

控制浮點值的格式

對於浮點值的格式化,可以控制下面三個方面:

  • 精度:顯示多少位數字。

  • 記數法:用小數還是科學記法法顯示。

  • 對是整數的浮點值的小數點的處理。

默認情況下,使用六位數字的精度顯示浮點值。如果值沒有小數部分,則省略小數點。使用小數形式還是科學記數法顯示數值取決於被顯示的浮點數的值,標準庫選擇增強數值可讀性的格式,非常大和非常小的值使用科學記數法顯示,其他值使用小數形式。

指定顯示精度

默認情況下,精度控制顯示的數字總位數。顯示的時候,將浮點值四捨五入到當前精度。因此,如果當前精度是 4,則 3.14159 成爲3.142;如果精度是 3,打印爲 3.14

通過名爲 precision 的成員函數,或者通過使用 setprecision 操縱符,可以改變精度。precision 成員是重載的(第 7.8 節):一個版本接受一個 int 值並將精度設置爲那個新值,它返回先前的精度值;另一個版本不接受實參並返回當前精度值。setprecision 操縱符接受一個實參,用來設置精度。

下面的程序說明控制顯示浮點值所用精度的不同方法:

// cout.precision reports current precision value
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;
     // cout.precision(12) asks that 12 digits of precision to be printed
     cout.precision(12);
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;
     // alternative way to set precision using setprecision manipulator
     cout << setprecision(3);
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;


編譯並執行後,程序產生下面的輸出:

Precision: 6, Value: 1.41421
     Precision: 12, Value: 1.41421356237
     Precision: 3, Value: 1.41


這個程序調用標準庫中的 sqrt 函數,可以在頭文件 cmath 中找到它。sqrt 函數量重載的,可以用 floatdouble 或 long double實參調用,它返回實參的平方根。

 

操縱符和其他接受實參的操縱符定義在頭文件 iomanip 中。

控制記數法

默認情況下,用於顯示浮點值的記數法取決於數的大小:如果數很大或很小,將按科學記數法顯示,否則,使用固定位數的小數。標準庫選擇使得數容易閱讀的記數法。

 

將浮點數顯示爲普通數(相對於顯示貨幣、百分比,那時我們希望控制值的外觀)的時候,通常最好讓標準庫來選擇使用的記數法。要強制科學記數法或固定位數小數的一種情況是在顯示錶的時候,表中的小數點應該對齊。

如果希望強制科學記數法或固定位數小數表示,可以通過使用適當的操縱符做到這一點:scientific 操縱符將流變爲使用科學記數法。像在十六進制值上顯示 x 一樣,也可以通過 uppercase 操縱符控制科學記數法中的 efixed 操縱符將流爲使用固定位數小數表示。

這些操縱符改變流精度的默認含義。執行 scientific 或 fixed 之後,精度值控制小數點之後的數位。默認情況下,精度指定數字的總位數——小數點之前和之後。使用 fixed 或 scientific 命名我們能夠按列對齊來顯示數,這一策略保證小數點總是在相對於被顯示的小數部分固定的位置。

恢復浮點值的默認記數法

與其他操縱符不同,不存在將流恢復爲根據被顯示值選擇記數法的默認狀態的操縱符,相反,我們必須調用 unsetf 成員來取消scientific 或 fixed 所做的改變。要將流恢復爲浮點值的默認處理,將名爲 floatfield 的標準庫定義值傳給 unsetf 函數:

// reset to default handling for notation
     cout.unsetf(ostream::floatfield);


除了取消它們的效果之外,使用這些操縱符像使用任意其他操縱符一樣:

cout << sqrt(2.0) << '\n' << endl;
     cout << "scientific: " << scientific << sqrt(2.0) << '\n'
          << "fixed decimal: " << fixed << sqrt(2.0) << "\n\n";
     cout << uppercase
          << "scientific: " << scientific << sqrt(2.0) << '\n'
          << "fixed decimal: " << fixed << sqrt(2.0) << endl
          << nouppercase;
     // reset to default handling for notation
     cout.unsetf(ostream::floatfield);
     cout << '\n' << sqrt(2.0) << endl;


產生如下輸出:

1.41421

     scientific: 1.414214e+00
     fixed decimal: 1.414214

     scientific: 1.414214E+00
     fixed decimal: 1.414214

     1.41421


顯示小數點

默認情況下,當浮點值的小數部分爲 0 的時候,不顯示小數點。showpoint 操縱符強制顯示小數點:

cout << 10.0 << endl;        // prints 10
     cout << showpoint << 10.0    // prints 10.0000
          << noshowpoint << endl; // revert to default handling of decimal point

noshowpoint 操縱符恢復默認行爲。下一個輸出表達式將具有默認行爲,即,如果浮點值小數部分爲 0,就取消小數點。

填充輸出

按欄顯示數據的時候,經常很希望很好地控制數據的格式化。標準庫提供下面幾個操縱幫助我們實現需要的控制:

  • setw,指定下一個數值或字符串的最小間隔。

  • left,左對齊輸出。

    right,右對齊輸出。輸出默認爲右對齊。

  • internal,控制負值的符號位置。internal 左對齊符號且右對齊值,用空格填充介於其間的空間。

  • setfill,使我們能夠指定填充輸出時使用的另一個字符。默認情況下,值是空格。

 

像 endl 一樣,setw 不改變輸出流的內部狀態,它只決定下一個輸出的長度。

下面程序段說明了這些操縱符:

int i = -16;
     double d = 3.14159;
     // pad first column to use minimum of 12 positions in the output
     cout << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column and left-justify all columns
     cout << left
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n'
          << right; // restore normal justification
     // pad first column and right-justify all columns
     cout << right
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column but put the padding internal to the field
     cout << internal
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column, using # as the pad character
     cout << setfill('#')
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n'
          << setfill(' '); // restore normal pad character


執行時,該程序段產生如下輸出:

i:          -16next col
     d:      3.14159next col
     i: -16         next col
     d: 3.14159     next col
     i:          -16next col
     d:      3.14159next col
     i: -         16next col
     d:      3.14159next col
     i: -#########16next col
     d: #####3.14159next col


A.3.4. 控制輸入格式化

默認情況下,輸入操作符忽略空白(空格、製表符、換行符、進紙和回車)。對下面的循環:

while (cin >> ch)
         cout << ch;


給定輸入序列

a b   c
     d


循環執行四次從字符 a 讀到 d,跳過介於其間的空格、可能的製表符和換行符。該程序段的輸出是:

abcd

noskipws 操縱符導致輸入操作符讀(而不是跳過)空白。要返回默認行爲,應用 skipws 操縱符:

cin >> noskipws;      // set cin so that it reads whitespace
     while (cin >> ch)
             cout << ch;
     cin >> skipws; // reset cin to default state so that it discards whitespace


給定與前面相同的輸入,該循環進行 7 次迭代,讀輸入中的空白以及字符。該循環產生如下輸出:

a b    c
     d

A.3.5. 未格式化的輸入/輸出操作

迄今爲止,示例程序中只使用過格式化的 IO 操作。輸入和輸出操作符(<< 和 >>)根據被處理數據的類型格式化所讀寫的數據。輸入操作符忽略空白,輸出操作符應用填充、精度等。

標準庫還提供了豐富的支持未格式化 IO 的低級操作,這些操作使我們能夠將流作爲未解釋的字節序列處理,而不是作爲數據類型(如charintstring 等)的序列處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章