C 快速上手 數值轉換字串方法小結

2021-10-01 07:22:37 字數 4346 閱讀 1987

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 ...