stringstream
to_string
c++17的std::to_chars
效能對比
在c++程式設計中,我們經常遇到的乙個基礎問題是型別轉換,比如將某個數值型別的變數(整型或者浮點型)轉換成文字字串的一部分展示給使用者,這個時候我們就需要將數值型別轉換成字串。特別是這種轉換十分頻繁的時候,我們希望轉換的方式是不容易出錯且效率非常高的。在這篇文章中,我將系統地總結c++中將數值型別轉換成字串的各種方法並從效率和**魯棒性的方面對各個方法進行比較。
在c++17之前我們主要有如下集中方式將數值型別轉換為字串:
std::sprintf 和std::snprintf包含在標頭檔案中,函式簽名如下:
int sprintf( char* buffer, const char* format, ... );
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );
其中,buffer是指向目標字串位址的指標,format是以「%d」開頭,以「\0」結尾的c風格字串,定義數值以何種方式輸出到目標字串中。sprintf將數值轉換成「format」字串定義格式的字串並在末尾加上null terminator,最後寫入到buffer指定的字串儲存空間中。這種方法的乙個顯著問題是sprintf函式本身不負責任何的記憶體管理,因此這種方法比較發生寫越界的錯誤。
為了提高寫入安全性,c++11引入了snprintf,相比較sprintf,這個函式多了buf_size這個引數來指定寫入buffer的字串的最大長度:最多buf_size - 1個字元(不包含結尾的null terminator)會被寫入buffer的位址空間。
兩個函式的函式返回值均為轉換後除去null terminator的字元個數,對於snprintf,如果返回值小於buf_size,則buffer中只會寫入部分轉換後的字串。在出錯的情況下函式返回 -1。
#include #include #include std::string str(15, ' ');
uint32_t integer = 100;
auto result_1 = sprintf(str.data(), "%d", interger);
auto result_2 = snprintf(str.data(), str.size(), "%d", integer);
stringstream包含在標頭檔案 當中,利用stringstream可以方便的以流運算子 << 將數值以各種格式或者進製寫入stringstream物件中,不用擔心寫越界的問題,同時可方便地與其他字串拼接在一起。但是相對於其他轉換方法stringstream的效率比較低,一方面寫入時的動態記憶體分配需要一定的開銷,另一方面其成員函式str()在取出字串時會進行一次字串的值拷貝操作。
#include std::stringstream ss;
std::string result;
uint32_t integer = 100;
ss << std::hex << integer << " is a hex number.";
c++11提供了std::to_string來將數值轉換成字串,std::to_string包含在標頭檔案中,該函式對多種數值型別進行了過載,使用起來非常方便,可以看作是sprintf 「c++化」的使用方法,因為它具備了根據型別處理,丟擲異常以及自動記憶體管理。缺點同樣是字串動態記憶體分配帶來的開銷和可能丟擲異常,另外std::to_string在轉換格式上依賴於執行環境的設定並不能進行精確控制,如在進行浮點數轉換時無法指定精度,可能會出現和想象中不一樣的結果。std::to_string最大的好處還是提現在易用性上面。
std::string to_string( int value );
std::string to_string( long value );
std::string to_string( long long value );
std::string to_string( unsigned value );
std::string to_string( unsigned long value );
std::string to_string( unsigned long long value );
std::string to_string( float value );
std::string to_string( double value );
std::string to_string( long double value );
c++17中提供了更為高效和安全的std::to_chars,對整型和浮點數型別進行了過載。包含在標頭檔案中。
對於整數型別,函式宣告如下:
std::to_chars_result to_chars(char* first, char* last, type value, int base = 10);
type可以是所有的有符號和無符號整型型別。base是2~36之間的數,表示轉換後字串的進製,因此轉換後的字串中大於9的數字用a~z的小寫字母表示。
浮點數的函式宣告包含更多的引數:
std::to_chars_result to_chars(char* first, char* last, float_type value);
float_type可以表示float, double以及long double。呼叫這個函式將使用預設的「c」轉換的設定,相當於使用%f或者%e格式說明符來進行型別轉換。
to_chars還提供如下宣告:
std::to_chars_result to_chars(char* first, char* last, float_type value,
std::chars_format fmt);
使用者可以通過fmt字串來指定輸出格式。
完成版本的浮點數型別的to_chars宣告如下,使用者可以通過precision變數進一步指定轉換精度:
std::to_chars_result to_chars(char* first, char* last, float_type value,
std::chars_format fmt, int precision);
呼叫std::to_chars,若轉換成功,則轉換後的字串將寫入指標指向的[first, last)記憶體區間。
函式的返回值std::to_chars_result的定義如下:
struct to_chars_result ;
這個型別用來儲存轉換結果:
轉換成功: 轉換後的字串結尾沒有 null-terminator。ptr將指向轉換後字串最後乙個字元的下乙個字元,同時ec將等於std::errc的預設值。
無效引數:ptr將等於first,同時ec等於std::errc::invalid_argument。
轉換後的字串越界:ec等於std::errc::value_too_large,同時記憶體區間[first, last)中的內容處於未知狀態。
#include #include // to_chars
#include int main()
; const int value = 2019;
const auto res = std::to_chars(str.data(),str.data() + str.size(), value);
if (res.ec == std::errc())
else
return 0;
}
執行結果如下:
輸入輸出
2019
2019**** filled: 4 characters
-2019
-2019****, filled: 5 characters
20192019
20192019, filled: 8 characters
-20192019
value too large! (the buffer is only 8 characters)
為了對比各種方法的執行效率,我進行了如下測試:
重複1000次
測試**中to_chars部分如下,完整**詳見benchmark:
template void run(const char* title, tfunc func)
void benchmark(uint32_t times, uint32_t size)
}});
}
C 字串 string 和數值轉換方法
記錄一下在做題時的一大重點,字串和數值轉換的方法 1 stringstream流轉換 需匯入標頭檔案 include 既可以將字串轉換為數值,也可以將數值轉換為字串,但需要注意轉換型別。關於字串流的涉及轉換的其它內容就不寫了,只說下轉換 include include include 標頭檔案 2 ...
C 字串轉換為數值型
引言 字串處理中,常常需要把字串轉換成數值型。方法有很多,這裡總結兩種比較簡單的方法。方法一c 自帶函式atoi char s 函式原型 include atoi char s 參考 方法二利用stringstream字串輸入輸出流 include include include using nam...
C 字串和數值間轉換
主要是用到字元流istringstream ostringstream的特性 string to double.the same way works for string to int.double string to double string s stoi方法 類似有stod方法 string ...