學校網站群建設方案找個網站
文章目錄
- 小結
- 問題及解決
- 參考
小結
使用sprintf(...)
進行格式化是一種標準的做法,但是這樣做是有一個極大的風險,由于sprintf(...)
不進行邊界檢查,這樣會有寫操作溢出邊界的風險,并導致程序崩潰。本文進行了簡單寫操作溢出邊界的測試,模擬程序崩潰,并建議了更為安全的snprintf(...)
方法進行格式化。
問題及解決
眾所周知,sprintf(...)
不進行邊界檢查,再加上double
或者是float
的內建的數據類型一起使用(有時候會是一個比較大的正數),比較容易出現(xiàn)寫操作溢出邊界并導致程序崩潰,已經是臭名昭著了。
以代碼sprintf(str, "%.2fMB(%.2f%%)", double_a, double_b);
為例。
sprintf
的說明指示符%.2f
規(guī)定了小數點后面截取兩位,但小數點前面有多少位就采用多少位,例如像2.4008127812204012E+159
這樣的大數,基本上小數點前面就超過160位數字了。如果數組str
比較小,就抓瞎了,寫操作會溢出邊界,并致程序崩潰。這種錯誤有時候極難定位,浪費很多寶貴的時候來找bug。
如果采用比較安全的做法, 例如: snprintf(str_short, 30, "%.2fMB(%.2f%%)", double_a, double_b);
,規(guī)定了邊界,只寫入前29位(最后再加一個結尾符),這樣就不用擔心寫操作會溢出邊界的問題了。
以下是程序測試很好地模擬了幾種情況(double_a
是一個很大的數,double_b
是一個很小的數):
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;//以下代碼不會出現(xiàn)溢出邊界,程序正常運行sprintf(str, "%.2fMB(%.2f%%)", double_a, double_b);cout << "str string = " << strStorage << endl;//以下代碼會出現(xiàn)溢出邊界并導致程序崩潰, 注釋之//sprintf(str_short, "%.2fMB(%.2f%%)", double_a, double_b);//cout << "str_short string = " << str_short<< endl;//以下代碼是比較安全的做法,進行有效的邊界檢查, 不會出現(xiàn)溢出邊界,程序正常運行,輸出了29位數字(后接一個結尾符)snprintf(str_short, 30, "%.2fMB(%.2f%%)", double_a, double_b);cout << "str_short string = " << str_short<< endl;system("pause");return 0;
輸出結果:
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