c格式化字串

2021-03-04 09:56:14 字數 3758 閱讀 9855

格式化字串——以c++的名義 (zt)

2009-12-22 10:59

從第一堂c語言課上的那個printf開始,格式化字串就成了我的夢魘。此後我還在很多地方遇到過它們:fprintf,sscanf以及cstring的format成員函式……。

除了能記住%s(string的縮寫)代表字串,%d(decimal的縮寫)代表整數之外,每次用到格式化字串的地方我都要求助於msdn。

直到我看到c++的字串格式化方式後,我決定從此拋棄c的那套格式化字串的方法。

在c++裡格式化字串,用到的最多的類是:ostringstream以及它的寬字元版本wostringstream。

話不多說,如果要將乙個整數n格式化成字串以便輸出之用

cstring的方式是這樣的:

cstring str;

str.format(_t("%d"), n);

ostringstream的方式:

ostringstream ost;

ost

拋開效率不談,起碼不用再去記%d代表整數,%f代表浮點數,當然還有更複雜的格式控制輸出的那些%(此處省略……)。

稍微複雜一點,如果要將整數以16進製制的格式輸出(這個恐怕是整數輸出中最常用的功能了)

ostringstream ost;

ost< 把乙個位元組序列以16進製制的方式輸出,最常見的情況比如16進製制的方式輸出mac位址:

ost< ost< 一定是輸出乙個int,否則無效。

如果以16進製制大寫的格式輸出:

ostringstream ost;

ost< 可有時候希望以32位整數的方式來輸出的時候,在前面通常要補上多個0,這時可以這樣做:

ostringstream ost;

// 也許有更好的寫法

ost<<"0x"< 比起格式化字串來輸入的字母更多,但我覺得這種以人話寫出來的方式比較好記:)

對於浮點數,最長用的格式化功能莫過於在小數點後保留x位的做法。

比如在小數點後保留6位:

ostringstream ost;

// 將輸出1234.567800

ost< 保留3位

// 將輸出1234.568,已經替我們做好了四捨五入

ost< 實現機制

c++使用一種稱為操控符的技術來控制格式化的輸出。

經典的hello world的c++版本大概是這樣的:

std::cout<<"hello world"< 對endl的輸出將引發下面這個過載了的《運算子的呼叫(摘自vs2008的ostream檔案):

_myt& __clr_or_this_call operator<<(_myt& (__cdecl *_pfn)(_myt&))

call basic_ostream manipulator

_debug_pointer(_pfn);

return ((*_pfn)(*this));

} 而endl正好滿足了這個過載的運算子的引數的格式:

_crtimp2_pure inline basic_ostream >&

__clrcall_or_cdecl endl(basic_ostream >& _ostr)

insert newline and flush byte stream

_ostr.put(' ');

_ostr.flush();

return (_ostr);

} 這樣:cout< 再來看個稍微複雜點的,看看語句ost< 在iomanip.cpp裡找到setprecision的函式定義:

_mrtimp2 _**anip __cdecl setprecision(streamsize prec)

manipulator to set precision

return (_**anip(&spfun, prec));

} 發現這個函式返回了乙個_**anip型別的物件。streamsize的型別是int,這裡的prec肯定是傳過來的3,那構造_**anip物件時的另乙個引數spfun是什麼東西?

同樣是在iomanip.cpp裡,spfun函式定義如下:

static void __cdecl spfun(ios_base& iostr, streamsize prec)

set precision

iostr.precision(prec);

發現在這個函式的內部,對流iostr呼叫了precesion函式。

運算子《有這樣乙個過載的版本:

template class _traits,

class _arg> inline

basic_ostream<_elem, _traits>& __clrcall_or_cdecl operator<<(

basic_ostream<_elem, _traits>& _ostr, const _**anip<_arg>& _manip)

insert by calling function with output stream and argument

(*_manip._pfun)(_ostr, _manip._manarg);

return (_ostr);

} 這樣,第乙個引數就是cout,而第二個引數就是setprecision函式返回的乙個臨時的_**anip型別的物件。在《運算子內部,如果(*_manip._pfun)(_ostr, _manip.

_manarg);就是呼叫spfun函式並將cout和3傳過去就好了!

go on!看看_manip._pfun到底是什麼東西:

// template struct _**anip

template

struct _**anip

store function pointer and argument value

_**anip(void (__cdecl *_left)(ios_base&, _arg), _arg _val)

pfun(_left), _manarg(_val)

construct from function pointer and argument value

}void (__cdecl *_pfun)(ios_base&, _arg); // the function pointer

_arg _manarg; // the argument value

既然當初在setprecision函式裡,傳遞的是spfun,那麼_pfun就是spfun函式的指標啦。ok,大功告成!c++的表現力很強大吧!

雖然繞了這麼大乙個彎子只不過為了呼叫一下cout.precision(3),那為什麼不這樣寫?

cout.precision(3);

cout<<1234.5678;

顯然寫成一條語句ost<

ostringstream使用時的乙個小技巧:

當用ostringstream格式化完畢後,通過呼叫它的str成員函式可以得到格式化後的字串:

ostringstream ost;

// 格式化的工作

……string str = ost.str();

如果接下來要繼續在這個流物件上進行其它的格式化工作,那麼要先清空ostringstream的快取,傳遞乙個空字串就好。

ost.str("");

這是個gui盛行的年代,從標準輸入顯得已經不那麼重要了,但是從檔案讀入依然是個很重要的操作,可我一直都是用winapi進行檔案的讀寫的,以後也許會再寫一片與格式化輸入有關的文章。

C字串函式大全

字串1 字串的長度用length表示,string s hello!int l 越界時會出現indexoutofrang 2 複製字串 string string1 how do you do string string2 string1 copy 函式。string string2 copyto ...

C語言字串函式大全

函式名 stpcpy 功能 拷貝乙個字串到另乙個 用法 char stpcpy char destin,char source 程式例 include include int main void 函式名 strcat 功能 字串拼接函式 用法 char strcat char destin,char...

C語言陣列和字串

實驗10 陣列和字串 實驗目的 1 理解一維陣列和二維陣列在記憶體中的存放形式。2 掌握一維陣列和二維陣列變數的定義和陣列元素的引用。3 掌握字串庫函式的用法。4 掌握字串和字元陣列的區別。實驗準備 1 一維陣列的定義。定義形式如下 儲存型別符資料型別符陣列變數名 整形常量表示式 如 int a 1...