2012年1月22日 星期日

C++: int 轉字串測試

輸出整數型別 (Integer) 或許是我們最常需要使用的功能之一。

網路上常見的建議為:
在 C 語言,我們常用 sprintf snprintf 來操作。
在 C++ ,我們可以使用 stringstream 來轉換。
另外,也可以使用 boost 來轉換。

這三種各有優缺點,在 The String Formatters of Manor Farm 一文中針對整數轉字串做了一個完整的分析。
在這裡,我們不考慮是否會發生緩衝區溢位的問題 (sprint),也不考慮程式碼是否容易辨別 (我們都把它包成一個函式)。那,到底誰最快呢?

在 boost 網站上有他們自己做的測試

不過我還是喜歡自己測,眼見為憑。
我寫了一支小程式 CastIntToStringTest.cc ,其中我將 snprintf 和 ostringstream 重新包裝成下列函式。

char *IntToPtr(int i)
{
  static char buf[50];
  snprintf(buf, sizeof(buf), "%d", i); 
  return buf;
}

string IntToString(int i)
{
  ostringstream oss;
  oss << i;
  return oss.str();
}
我的 g++ 版本為 gcc version 4.6.2 (Debian 4.6.2-12) OS 為 Debian sid (2012-1-22) 跑在 VirtualBox 上面 Host 為 Mac Mini Server (Core 2 Due 版),OS 為 Lion。 執行結果如下
hialan@debian:~$ ./CastIntToStringTest 
Test IntToPtr: 123456
Test IntToString: 123456
Test lexical_cast: 123456
Run 10000000 times.

IntToPtr: 2 secs.
IntToString: 11 secs.
lexical_cast<string>: 4 secs.
hialan@debian:~$

在官方做的測試中,int -> string 的轉換結果為
lexical_cast : 20
std::stringstream with construction : 121
std::stringstream without construction : 21
scanf/printf : 16

我想差距不大。假設官方的測試結果是 ok 的。

不過我的測試只針對單一型別做轉換。在嚴格條件下可以針對這類案例做最佳化。
但如果是要一般化的解決方案,我想用 lexical_cast 是不錯的選擇。程式碼精簡明確,又可套用在不同型別。
而且結果比 sringstream 好上太太太多了。

至於 sprintf ? 如果想要自己處理記憶體的話,可能是個好選擇。