字串格式化

2021-04-21 05:36:59 字數 4589 閱讀 6459

sprintf

_snprintf(snprintf)

std::stringstream

std::strstream

boost::lexical_cast

boost::format

cstring::format

1

sprintf

使用

sprintf

不安全,輕則破壞資料的準確性,重則程式崩潰。請看下面的程式片段:

cstring

strtest

= "hello"

;

1inta=

10;2

char

tbuf[10

];

3sprintf

(tbuf

, "%s,%d"

, "0123456789 0123456789 0123456789 0123456789",

a); 4

printf

("%s/n"

, tbuf

); 5if

(10== a

)

6strtest

.insert(0

, "abc"

);

7printf

("%s/n"

, strtest

.getbuffer(0

));

編譯一下,沒問題,

0 error(s), 0 warning(s)。

看看輸出來的結果,很幸運,執行第

4行輸出

tbuf

格式的字串,跟想要的結果一致的。但奇怪的問題出現了,

a的數值只有初始化賦值為

10,沒其他地方給它賦值了,為宣告不會執行第

6行,更奇怪的是執行第

7行拋異常了。其實原因就是,

sprintf,

在幕後偷偷的修改了

a的值,並且破壞了

strtest

這個物件。

類似的錯誤還有想這樣的**

:

inti, a

[10];

for(i=

0; i<=

10; ++i)

a[i] = 0;

本來想給陣列

a初始化,沒想到的是,程式進入了乙個死迴圈。

i (a[10])

0x0012ff54

a[9]

0x0012ff50

a[8]

0x0012ff4c

a[7]

0x0012ff48……

通常情況下,棧是往記憶體的低位址方向增長的,也就是說,現壓棧的內容存放在高位址區域,後壓棧的內容存放在低位址區域。

2

_snprintf

sprintf

處的**改為用

_snprintf,

看看結構如何。

_snprintf

(tbuf

,sizeof(

tbuf

)-1,

"%s,%d"

, "0123456789 0123456789 0123456789 0123456789",

a);

我們一看結果就知道是緩衝區不夠了,這樣容易發現問題,也不會破壞程式記憶體。注意,即便這樣,仍然還存在另外一種出錯的可能,即呼叫者將緩衝區的長度搞錯了。

3

std::stringstream

ostringstream temp;

temp<<"0123456789 0123456789 0123456789 0123456789,"

sprintf

和std::stringstream

的優缺點: 1)

.sprintf

具有易用性和清晰性,而

std::stringstream

比較臃腫了,至少要三行**實現。 2)

.sprintf

位元組利用緩衝區,效率高。而

std::stringstream

要儘管多次拷貝,有可能還要多次動態分配記憶體。 3)

.std::stringstream

動態分配記憶體,所以長度是安全的,不會出現破獲記憶體的情況 4)

.std::stringstream

模版型別安全,方便。而

sprintf

有可能把乙個整數格式到

%s4.std::strsteam

char

tbuf[10

];

std::

strstream

temp

(tbuf

, sizeof

(tbuf

));

temp<<"0123456789 0123456789 0123456789 0123456789,"<效果跟

_snprintf

差不多,但是它要自己手動加上

『/0』

字串結束符。而且至少要寫兩行**。優點也是長度安全,型別安全,有模版的親和性。我個人來說不喜歡用。

5.boost::lexical_cast

strings=

"0123456789 0123456789 0123456789 0123456789,"+

boost

::lexical_cast

<

string

>(

a);

實際上lexical_cast

的目的只是為了將資料從乙個可流化的型別轉換為另乙個可流化的型別。就類似

atoi, itoa,

等之類的函式。做格式化一串資料感覺就不是很好了。

6.boost::format

boost

::format

fs=

boost

::format

("%1%,%2%"

) %"0123456789 0123456789 0123456789 0123456789"% a

; //string ss = fs.str();

boost

::format

簡潔優雅,長度安全,型別安區。只是由於記憶體是動態分配的,效率上比

sprintf, _snprintf

稍低一點。但如果我們的專案使用了

boost

庫,用boost::format

總體上比

sprintf,_snprintf

都好一點。

7mfc

中的cstring

如果決定用

mfc庫,並且以後不會移植的話,最好就用

cstring。

cstrings;

s.format

("%s,%d"

, "0123456789 0123456789 0123456789 0123456789", a

);

但是它要表明格式的型別和

sprintf, _snprintf

一樣,型別並不是總是安全的。

總結:通常情況下考慮效率使用

_snprintf

最好,如果使用

boost

庫,且對執行效率沒有苛刻的要求請使用

boost

::format

,如果使用了

mfc,且又不考慮以後的移植,請使用

cstring。

補充:我們經常對字串的拷貝同樣有兩

c標準函式

:

char *strcpy( char * strdest, const char *strsource );

char *strncpy( char *strdest, const char *strsource, size_t count );

萬一我們的

strdest

緩衝區長度不夠,同樣會破壞記憶體,使程式崩潰。

例如:char

tbuf[10

]=;

string

strsrc

= "hello, i'm string"

;

strcpy

(tbuf

, strsrc

.c_str

());改為

strncpy

(tbuf

, strsrc

.c_str

(),

min(

sizeof

(tbuf)-1

,strsrc

.size

()));

那就安全了。

上面這些都是一些自己在開發過程中的總結和心得,希望對朋友們有幫助!

格式化字串

通常在使用字串的時候,會對字串進行格式化,然後輸出或呼叫 一般我們使用替換標記對字串進行格式化 string str1 string.format add is 1,2,3 而且在c 中的替換標記可以以任意順序和次數出現在格式化字串中,但替換值是按順序排的,而且替換標記不能超出索引範圍 string...

字串格式化

例如 string s hello map.put target world string res format s,map 有什麼用呢?比如在some.properties中配置模板字串,但是如果用 這種方式,在配置了spring讀取properties注入變數的時候,這個變數就找不到會報錯。這個...

格式化字串

格式化字元 格式化字元 描述 f或f 格式化浮點數 e或e 用指數計數法格式化數字 p或p 格式化百分數 n或n 用逗號分隔符格式化數字 c或c 格式化本地貨幣值 d或d 格式化十進位制數 g或g 用浮點數或指數計數法格式化數字 x或x 將浮點數轉化為十六進製制 格式化變數中0指第乙個變數,6表示顯...