Boost(4)lexical_castとatoi,atofを調べる
公開日| 2009年09月10日 | コメントはまだありません。
カテゴリー:BOOST |
概要 : 今回の記事は、Boostで色々な情報へキャストすることができるlexical_castを使ってみます。
lexical_castは、STLのstringからdoubleやintへの変換もできます。C言語では、atof,atoi などを使って変換します。 C++では、std::istringstreamからのシフト演算子(>>)を使って変換できます。
上記の3つの違いについて、簡単に調べてみたいと思います。
では、早速、サンプルソースを使って試してみましょう。
ここで使用したサンプルソースコード:
コンソールアプリケーションで試してみましょう
簡単に動作確認するために、以下のようなサンプルプログラムを作成してみました。では、早速、ソースコードを見てみましょう。
[sample.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #include <iostream> #include <string> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> using namespace std; using namespace boost; struct _test_value { const char *_char; const wchar_t *_wchar; }; static _test_value double_test[] = { { "hello world!123" , L"hello world!123" }, { "12345" , L"12345" }, { " 12345" , L" 12345" }, { "12345 " , L"12345 " }, { " 12345 " , L" 12345 " }, { "123.45" , L"123.45" }, { "6.543E+099" , L"6.543E+099" }, { "6.543e+099" , L"6.543e+099" }, { "1.2345e+999" , L"1.2345e+999" }, // stopper { NULL,NULL } }; int main(int argc, char *argv[]) { string str1; wstring str2; double db; int ni=0; cout << "== double convert" << endl; while(double_test[ni]._char!=NULL){ str1=double_test[ni]._char; str2=double_test[ni]._wchar; try{ db=lexical_cast<double>(str1); cout << str1 << ":"<< db << endl; } catch(bad_lexical_cast &e) { cout << str1 << "(error):" << e.what() << endl; } try{ db=lexical_cast<double>(str2); cout << str1 << ":"<< db << endl; } catch(bad_lexical_cast &e) { cout << str1 << "(error):" << e.what() << endl; } std::istringstream ss(str1); //std::wistringstream ss(str2); ss >> db; if(!(ss && (ss >> std::ws).eof())){ cout << "cast(error):"<< str1 << ":"<< db << endl; } else { cout << "cast:"<< str1 << ":"<< db << endl; } db=atof(str1.c_str()); cout << "atof:"<< str1 << ":"<< db << endl; cout << endl; ni++; } int nb; ni=0; cout << "== int convert" << endl; while(double_test[ni]._char!=NULL){ str1=double_test[ni]._char; str2=double_test[ni]._wchar; try{ nb=lexical_cast<int>(str1); cout << str1 << ":"<< nb << endl; } catch(bad_lexical_cast &e) { cout << str1 << "(error):" << e.what() << endl; } try{ nb=lexical_cast<int>(str2); cout << str1 << ":"<< nb << endl; } catch(bad_lexical_cast &e) { cout << str1 << "(error):" << e.what() << endl; } std::istringstream ss(str1); ss >> nb; if(!(ss && (ss >> std::ws).eof())){ cout << "cast(error):"<< str1 << ":"<< nb << endl; } else { cout << "cast:"<< str1 << ":"<< nb << endl; } nb=atoi(str1.c_str()); cout << "atoi:"<< str1 << ":"<< nb << endl; cout << endl; ni++; } string strss; cin >> strss ; // any key input!! --> exit. return 1; } |
このプログラムは、double_testのテストデータ(8bit文字列、UNCODE文字列)を順次変換して、 その結果を出力しています。UNCODE文字列については、lexical_castでのみ変換しています。
では、簡単に解説をしてみます。
38行目は、テストデータが終わりかどうかを判断しています。
44行目、51行目は、lexical_castによるdoubleへの変換処理を実施しています。変換に失敗するとbad_lexical_castがスローされます。
変換の仕方は、以下のように指定します。戻り値が、変換結果となります。
lexical_cast<変換したいクラス名>(変換するオブジェクト)
57行目から64行目は、C++言語のSTLを用いた変換を行っています。 60行目でエラーチェックを行っていますが、今回は、すべての文字列が変換処理を実施したかどうかで判断しています。
66行目は、C言語によ変換を行っています。atof,atoiでは、エラーの確認はできません。
以降は、intへの変換です。処理の概要は同じですので、説明を割愛いたします。
実際に、実行してみると、以下がその実行結果が表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | == double convert hello world!123(error):bad lexical cast: source type value could not be interpreted as target hello world!123(error):bad lexical cast: source type value could not be interpreted as target cast(error):hello world!123:-9.25596e+061 atof:hello world!123:0 12345:12345 12345:12345 cast:12345:12345 atof:12345:12345 12345(error):bad lexical cast: source type value could not be interpreted as target 12345(error):bad lexical cast: source type value could not be interpreted as target cast: 12345:12345 atof: 12345:12345 12345 (error):bad lexical cast: source type value could not be interpreted as target 12345 (error):bad lexical cast: source type value could not be interpreted as target cast:12345 :12345 atof:12345 :12345 12345 (error):bad lexical cast: source type value could not be interpreted as target 12345 (error):bad lexical cast: source type value could not be interpreted as target cast: 12345 :12345 atof: 12345 :12345 123.45:123.45 123.45:123.45 cast:123.45:123.45 atof:123.45:123.45 6.543E+099:6.543e+099 6.543E+099:6.543e+099 cast:6.543E+099:6.543e+099 atof:6.543E+099:6.543e+099 6.543e+099:6.543e+099 6.543e+099:6.543e+099 cast:6.543e+099:6.543e+099 atof:6.543e+099:6.543e+099 1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target 1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target cast(error):1.2345e+999:6.543e+099 atof:1.2345e+999:1.#INF == int convert hello world!123(error):bad lexical cast: source type value could not be interpreted as target hello world!123(error):bad lexical cast: source type value could not be interpreted as target cast(error):hello world!123:-858993460 atoi:hello world!123:0 12345:12345 12345:12345 cast:12345:12345 atoi:12345:12345 12345(error):bad lexical cast: source type value could not be interpreted as target 12345(error):bad lexical cast: source type value could not be interpreted as target cast: 12345:12345 atoi: 12345:12345 12345 (error):bad lexical cast: source type value could not be interpreted as target 12345 (error):bad lexical cast: source type value could not be interpreted as target cast:12345 :12345 atoi:12345 :12345 12345 (error):bad lexical cast: source type value could not be interpreted as target 12345 (error):bad lexical cast: source type value could not be interpreted as target cast: 12345 :12345 atoi: 12345 :12345 123.45(error):bad lexical cast: source type value could not be interpreted as target 123.45(error):bad lexical cast: source type value could not be interpreted as target cast(error):123.45:123 atoi:123.45:123 6.543E+099(error):bad lexical cast: source type value could not be interpreted as target 6.543E+099(error):bad lexical cast: source type value could not be interpreted as target cast(error):6.543E+099:6 atoi:6.543E+099:6 6.543e+099(error):bad lexical cast: source type value could not be interpreted as target 6.543e+099(error):bad lexical cast: source type value could not be interpreted as target cast(error):6.543e+099:6 atoi:6.543e+099:6 1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target 1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target cast(error):1.2345e+999:1 atoi:1.2345e+999:1 |
この結果を簡単に表にまとめてみました。
| Boost lexical | std::istringstream | atoi/atof | |
| 文字列あり | x | x | x (0) |
| 整数値 | o | o | o |
| 整数値(空白あり(前)) | x | o | o |
| 整数値(空白あり(後)) | x | o | o |
| 整数値(空白あり(前後)) | x | o | o |
| 小数値 | o | o (*1) | o (*1) |
| 小数値(E表現) | o | o (*1) | o (*1) |
| 小数値(e表現) | o | o (*1) | o (*1) |
| 小数値(e表現オーバーフロー値) | x | x (*1) | x (*1) |
このように、lexical_castのチェックは、非常に厳格です。
前後の半角ブランクがあるだけでもNGとなります。
それに比べて、C/C++での変換は、半角ブランクがあっても変換できます。
昨今では、atoi,atofを多用しているプログラムは、あまり無いとは思いますが、
atoi,atofの代わりに、lexical_castをそのまま用いようとするとエラーが発生して、うまく動作しないかもしれませんね。
また、lexical_castは、int,doubleなどの数値変換だけでなく、数値から文字列への変換などもできます。非常に便利なものです。
色々と試されることをお勧めします。
また、lexical_castは、int,doubleなどの数値変換だけでなく、数値から文字列への変換などもできます。非常に便利なものです。
色々と試されることをお勧めします。
もっと、Boostについて詳しく知りたい方は、以下の本なども良いと思います。本から学ぶことは多いと思います。ネットだけでは判らない様々な事に気づかされます。
![]() Boost C++ Libraryプログラミング | ![]() Boost C++ Librariesプログラミング | ![]() Boost C++をチューンアップする最先端ライブラリ |




