C++格式化輸入輸出

AngryBill發表於2014-03-02

C++共有15個  輸入輸出   格式標記位,這15個標記位均為bit位,每個標記位都有自己的含義,且可以單獨設定。

格式標記位的取值為0或1:0表示關閉(不使用此格式),1表示開啟(使用此格式)。

15個標記位的含義可參考下面三張表:

標記位

含義

boolalpha 如開啟,則輸入和輸出使用bool值(即Ture或False)
showbase 如開啟,則對於輸出,使用C++ 基數字首(0,0x)
showpoint 如開啟,則顯示末尾的小數點
uppercase 如開啟,則對於16進位制,使用大寫字母;對於10進位制,使用E表示法
showpos 如開啟,則在正數前面加上+

標記位

含義

dec 如開啟,則使用基數10(進行輸出)
oct 如開啟,則使用基數8
hex 如開啟,則使用基數16
fixed 如開啟,則使用定點計數法
scientific 如開啟,則使用科學計數法
left 如開啟,則使用左對齊
right 如開啟,則使用右對齊
internal 如開啟,則符號或基數字首左對齊,值右對齊

標記位

含義

skipws 如開啟,則跳過輸入流中的空白字元
unitbuf 如開啟,則每次輸出操作後都會清空緩衝區

先來看一個簡單的程式:

#include <iostream>
using namespace std;

int main()
{
    int x;
    x = cout.setf(ios::showpos);
    cout << x << endl;
    
    x = cout.setf(ios::uppercase);
    cout << x << endl;
    
    system("pause");
    return 0;
}
輸出結果是:

 setf()函式用於設定格式標記,函式接受一個設格式常量作為引數,在設定成功之後函式會返回一個值,該值指出了所有15個標記的上一次設定情況。

但將這個返回值進行輸出,並不是每一個標記位的bit值,而是一個整數,為什麼?

實際上,這15個bit值視為一個整體,從而組成一個二進位制數,並能夠轉化為十進位制數。

這15個標記位的排列順序是:

uppercase unitbuf   skipws  showpos showpoint  showbase  scientific right oct  left internal hex fixed dec boolalpha

  比如,setf()函式第一次的返回值是4098,這個值實際上是輸出格式的初始狀態,轉化二進位制為001000000000010,那麼格式狀態為:

uppercase unitbuf   skipws  showpos showpoint  showbase  scientific right oct  left internal hex fixed dec boolalpha
0 0 1 0 0 0 0 0 0 0 0 0 0 1 0

而6146轉化為二進位制001100000000010,這一次的值反映的是開啟了showpos位後的格式狀態:

uppercase unitbuf   skipws  showpos showpoint  showbase  scientific right oct  left internal hex fixed dec boolalpha
0 0 1 1 0 0 0 0 0 0 0 0 0 1 0

兩次對比,我們可以看出,的確是在初始狀態的基礎上開啟了showpos位。

 

 接著我們來看看格式常量,格式常量一共有18個,其中15個用於開啟相應的格式標記為,另外3個做為指示功能用

 

#include <iostream>
using namespace std;

 

int main()
{
    cout << "boolalpha    " << ios::boolalpha <<endl;
    cout << "dec          " << ios::dec << endl;
    cout << "fixed        " << ios::fixed << endl;
    cout << "hex          " <<ios::hex << endl;
    cout << "internal     " << ios::internal << endl;
    cout << "left         " << ios::left << endl;
    cout << "oct          " << ios::oct << endl;
    cout << "right        " << ios::right << endl;
    cout << "scientific   " << ios::scientific << endl;
    cout << "showbase     " << ios::showbase <<endl;
    cout << "showpoint    " << ios::showpoint <<endl;
    cout << "showpos      " << ios::showpos <<endl;
    cout << "skipws       " << ios::skipws << endl;
    cout << "unitbuf      " << ios::unitbuf << endl;
    cout << "uppercase    " << ios::uppercase <<endl;
    
    cout << endl;
    cout << "basefield    " << ios::basefield << endl;
    cout << "adjustfield  " << ios::adjustfield << endl;
    cout << "floatfield   " << ios::floatfield << endl;
     
    system("pause");
    return 0;
}

 

 

格式常量

十進位制值

意義

ios::boolalpha

1

開啟boolalpha標記位,輸入和輸出使用bool值(即Ture或False)
ios::showbase

512

開啟showbase標記位,對於輸出,使用C++ 基數字首(0,0x)
ios::showpoint

1024

開啟showpoint標記位,顯示末尾的小數點
ios::uppercase

16384

開啟uppercase標記位,對於16進位制,使用大寫字母;對於10進位制,使用E表示法
ios::showpos

2048

開啟showpos標記位,在正數前面加上+

格式常量

十進位制值

意義

格式常量

十進位制值

意義

ios::basefield

74

指示相關標記位:dec、oct、hex ios::dec

2

開啟dec標記位,使用基數10
      ios::oct

64

開啟oct標記位,使用基數8
      ios::hex

8

開啟hex標記位,使用基數16
ios::floatfield

260

指示相關標記位:fixed、scientific ios::fixed

4

開啟fixed標記位,使用定點計數法
      ios::scientific

256

開啟scientific標記位,使用科學計數法
ios::adjustfield

176

指示相關標記位:left、right、internal ios::left

32

開啟left標記位,使用左對齊
      ios::right

128

開啟right標記位,使用右對齊
      ios::internal

16

開啟internal標記位,符號或基數字首左對齊,值右對齊

注意:這些都是常量,是作為 函式引數 來設定格式狀態,而不是格式標記位的儲存空間。

15個藍色的格式常量用來開啟對應的格式標記位,如果將其十進位制值轉化為二進位制,再於標記位順序表比對,就可以看出來。

3個綠色的格式常量用來指示標記位,為什麼要指示?比如:dec、oct、hex是不可能同時開啟的,而ios::basefield則指示這三個標記位為一組,74=2+64+8,這意味著它轉化為二進位制的比對情況是dec、oct、hex為1,但它不是設定標記位,而是指示,具體原理在setf()函式中詳細解釋。

最後來看看setf()函式:

setf()函式有兩種原型,一種是fmtflags  setf  ( fmtflags );

它接收一個引數,該引數是一種 標記型別,提供實參時,可以是整數,該整數轉化為二進位制後賦給格式狀態。但這種方法抽象且不安全。

也可以將格式常量作為實參提供給函式,在這種情況下,setf()函式會開啟相應的標記位,且不會影響其它標記位。但這種方法仍不安全。很明顯,既開啟dec標記位,又開啟oct標記位是沒有意義的。

 


 

另一種原型是fmtflags  setf  ( fmtflags , fmtflags );

它接收兩個 標記型別 的引數。第一個引數指出要開啟的標記位,第二個引數則是指示要清除的一批相關位。

比如:cout.setf( ios::hex, ios::basefield );  這表示使用16進位制輸出格式。首先,ios::basefield指示出了要清除的標記位,setf()函式將ios::basefield所指示的標記位,即dec、oct、hex全部清零。然後ios::hex使得setf()函式開啟hex標記位。這是一種安全的方法,避免了同時開啟dec、hex兩個標記位等沒有實際意義的情況發生。

                                                              

setf()是如何實現清除的?

ios::basefield轉化為二進位制000000001001010,這三個1的位置指示的是dec、oct、hex標記位。setf()函式將這個二進位制數取反111111110110101,然後與原格式狀態標記位進行“與”操作,使得原格式狀態的dec、oct、hex標記位為0,而其它標記位不變。(參看《C++ primer plus》683頁位操作)

然後setf()函式根據第一個引數ios::hex將格式狀態的hex標記位開啟,其它標記位不變。至此,格式設定就成功完成了。我們也可以看出,setf()函式不會影響無關標記位的狀態

相關文章