學(xué)校網(wǎng)站群建設(shè)方案找個(gè)網(wǎng)站
文章目錄
- 小結(jié)
- 問(wèn)題及解決
- 參考
小結(jié)
使用sprintf(...)
進(jìn)行格式化是一種標(biāo)準(zhǔn)的做法,但是這樣做是有一個(gè)極大的風(fēng)險(xiǎn),由于sprintf(...)
不進(jìn)行邊界檢查,這樣會(huì)有寫操作溢出邊界的風(fēng)險(xiǎn),并導(dǎo)致程序崩潰。本文進(jìn)行了簡(jiǎn)單寫操作溢出邊界的測(cè)試,模擬程序崩潰,并建議了更為安全的snprintf(...)
方法進(jìn)行格式化。
問(wèn)題及解決
眾所周知,sprintf(...)
不進(jìn)行邊界檢查,再加上double
或者是float
的內(nèi)建的數(shù)據(jù)類型一起使用(有時(shí)候會(huì)是一個(gè)比較大的正數(shù)),比較容易出現(xiàn)寫操作溢出邊界并導(dǎo)致程序崩潰,已經(jīng)是臭名昭著了。
以代碼sprintf(str, "%.2fMB(%.2f%%)", double_a, double_b);
為例。
sprintf
的說(shuō)明指示符%.2f
規(guī)定了小數(shù)點(diǎn)后面截取兩位,但小數(shù)點(diǎn)前面有多少位就采用多少位,例如像2.4008127812204012E+159
這樣的大數(shù),基本上小數(shù)點(diǎn)前面就超過(guò)160位數(shù)字了。如果數(shù)組str
比較小,就抓瞎了,寫操作會(huì)溢出邊界,并致程序崩潰。這種錯(cuò)誤有時(shí)候極難定位,浪費(fèi)很多寶貴的時(shí)候來(lái)找bug。
如果采用比較安全的做法, 例如: snprintf(str_short, 30, "%.2fMB(%.2f%%)", double_a, double_b);
,規(guī)定了邊界,只寫入前29位(最后再加一個(gè)結(jié)尾符),這樣就不用擔(dān)心寫操作會(huì)溢出邊界的問(wèn)題了。
以下是程序測(cè)試很好地模擬了幾種情況(double_a
是一個(gè)很大的數(shù),double_b
是一個(gè)很小的數(shù)):
char str[200];char str_short[30];double double_a= 2.4008127812204012E+159;double double_b= 1.3906711615670009E-309;cout << "double_a= " << double_a<< endl;cout << "double_b= " << double_b<< endl;//以下代碼不會(huì)出現(xiàn)溢出邊界,程序正常運(yùn)行sprintf(str, "%.2fMB(%.2f%%)", double_a, double_b);cout << "str string = " << strStorage << endl;//以下代碼會(huì)出現(xiàn)溢出邊界并導(dǎo)致程序崩潰, 注釋之//sprintf(str_short, "%.2fMB(%.2f%%)", double_a, double_b);//cout << "str_short string = " << str_short<< endl;//以下代碼是比較安全的做法,進(jìn)行有效的邊界檢查, 不會(huì)出現(xiàn)溢出邊界,程序正常運(yùn)行,輸出了29位數(shù)字(后接一個(gè)結(jié)尾符)snprintf(str_short, 30, "%.2fMB(%.2f%%)", double_a, double_b);cout << "str_short string = " << str_short<< endl;system("pause");return 0;
輸出結(jié)果:
double_a= 2.40081e+159
double_b= 1.39067e-309
str string = 2400812781220401246196118053255811918339999978374591715533604156445593861118215728144462510983065193819073699313679732935503602200085321608454731838025375940608.00MB(0.00%)
str_short string = 24008127812204012461961180532
Press any key to continue . . .
參考
sprintf(str,“%f”, voltage_temp ); works in C but not C ++
C++ Buffer Overflow: Format String (%f/%F)
Stackoverflow: understanding the dangers of sprintf(…)
C++ float and double