回答:
新しいC ++ 11には、stoi、stol、stoll、stoulなどの関数があります。
int myNr = std::stoi(myString);
変換エラー時に例外をスローします。
これらの新しい関数でも、Danが指摘したのと同じ問題があります。文字列「11x」を整数「11」に変換します。
詳細:http : //en.cppreference.com/w/cpp/string/basic_string/stol
size_t
が文字列の長さに等しくない場合は、早期に停止しました。それはまだその場合には11を返しますが、pos
代わりに文字列の長さ3の2になりますcoliru.stacked-crooked.com/a/cabe25d64d2ffa29
これが私の最初のアドバイスです。これにはstringstreamを使用しないでください。最初は使用するのは簡単に思えるかもしれませんが、堅牢性と優れたエラー処理が必要な場合は、多くの追加作業を行わなければならないことがわかります。
以下は、直感的に機能するように見えるアプローチです。
bool str2int (int &i, char const *s)
{
std::stringstream ss(s);
ss >> i;
if (ss.fail()) {
// not an integer
return false;
}
return true;
}
これは大きな問題がありますstr2int(i, "1337h4x0r")
喜んで返しますtrue
とi
値を取得します1337
。この問題を回避するにはstringstream
、変換後の文字がこれ以上なくなるようにします。
bool str2int (int &i, char const *s)
{
char c;
std::stringstream ss(s);
ss >> i;
if (ss.fail() || ss.get(c)) {
// not an integer
return false;
}
return true;
}
1つの問題を修正しましたが、他にもいくつか問題があります。
文字列の数値が10を基数としていない場合はどうなりますか?ss << std::hex
変換を試みる前に、ストリームを正しいモード(例:)に設定することで、他のベースに対応することができます。しかし、これは、発信者が数の基数をアプリオリに知る必要があることを意味します-発信者はどうすればそれを知ることができるのでしょうか?発信者は番号がまだ何であるか知りません。彼らはそれがそうであることさえ知りません数!どのようにして彼らはそれがどんなベースであるかを知ることが期待できますか?プログラムに入力する数値はすべて10を基数とし、16進数または8進数の入力を無効として拒否することを義務付けることができます。しかし、それは非常に柔軟でも堅牢でもありません。この問題に対する簡単な解決策はありません。10進数の変換は常に(先行ゼロ付きの)8進数に対して成功し、一部の10進数に対しては8進数の変換が成功する可能性があるため、単純に各基数に対して1回変換を試すことはできません。したがって、先行ゼロをチェックする必要があります。ちょっと待って!16進数も先頭にゼロを付けることができます(0x ...)。はぁ。
上記の問題に対処できたとしても、さらに別の大きな問題があります。呼び出し側が不正な入力(たとえば、「123foo」)と範囲外の数値int
(たとえば、「4000000000」 32ビットint
)?ではstringstream
、この区別をする方法はありません。変換が成功したか失敗したかのみがわかります。失敗した場合、なぜ失敗したかを知る方法はありません。ご覧のように、stringstream
堅牢性と明確なエラー処理が必要な場合は、多くのことが望まれます。
これにより、2つ目のアドバイスが表示されます。これにはBoostを使用しないでくださいlexical_cast
。lexical_cast
ドキュメントが言っていることを考慮してください:
変換に対してより高度な制御が必要な場合、std :: stringstreamおよびstd :: wstringstreamがより適切なパスを提供します。非ストリームベースの変換が必要な場合、lexical_castはジョブにとって不適切なツールであり、そのようなシナリオでは特別なケースではありません。
何??これstringstream
は制御レベルが低いことはすでに確認しましたが、「より高い制御レベル」が必要な場合stringstream
はlexical_cast
、代わりに使用する必要があると述べています。また、lexical_cast
は単なるラッパーであるためstringstream
、同じ問題がstringstream
発生します。複数の基数のサポートが不十分で、エラー処理が不十分です。
幸いなことに、誰かが上記の問題のすべてをすでに解決しています。C標準ライブラリにはstrtol
、これらの問題のないファミリが含まれています。
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
すべてのエラーケースを処理し、2から36までの任意の基数もサポートするものにとっては非常に単純です。base
ゼロ(デフォルト)の場合、任意の基数からの変換を試みます。または、呼び出し元は3番目の引数を指定して、特定のベースに対してのみ変換を試行するように指定できます。堅牢で、最小限の労力ですべてのエラーを処理します。
その他の好みstrtol
(および家族)の理由:
他の方法を使用する正当な理由は絶対にありません。
strtol
スレッドセーフである必要があります。POSIXではerrno
、スレッドローカルストレージを使用する必要もあります。非POSIXシステムでも、errno
マルチスレッドシステムのほぼすべての実装はスレッドローカルストレージを使用します。最新のC ++標準はerrno
、POSIXに準拠している必要があります。最新のC標準ではerrno
、スレッドローカルストレージも必要です。POSIXに完全に準拠していないWindowsでも、errno
スレッドセーフであり、ひいてはですstrtol
。
std::stol
はこれが含まれており、定数を返すのではなく、例外を適切にスローします。
std::stol
にこの回答を書いたのは、C ++言語にも追加されました。とはいえ、これが「C ++内のCコーディング」であると言っても不思議ではありません。それstd::strtol
が明示的にC ++言語の一部である場合、それがCコーディングであると言うのはばかげています。私の回答は、C ++が作成されたときに完全にC ++に適用されましたが、新しいstd::stol
。例外をスローする可能性のある関数の呼び出しは、すべてのプログラミング状況で常に最適であるとは限りません。
これはatoi()よりも安全なCの方法です。
const char* str = "123";
int i;
if(sscanf(str, "%d", &i) == EOF )
{
/* error */
}
標準ライブラリstringstreamを使用したC ++ :(CMSに感謝)
int str2int (const string &str) {
stringstream ss(str);
int num;
if((ss >> num).fail())
{
//ERROR
}
return num;
}
#include <boost/lexical_cast.hpp>
#include <string>
try
{
std::string str = "123";
int number = boost::lexical_cast< int >( str );
}
catch( const boost::bad_lexical_cast & )
{
// Error
}
編集:エラーを処理するようにstringstreamバージョンを修正しました。(元の投稿に対するCMSおよびjkのコメントに感謝)
古き良きCの方法はまだ機能します。strtolまたはstrtoulをお勧めします。戻りステータスと「endPtr」の間で、適切な診断出力を提供できます。また、複数の拠点を適切に処理します。
これをより一般的なインターフェースでラップするBoostlexical_cast
を使用できます。
失敗時にスローします。lexical_cast<Target>(Source)
bad_lexical_cast
C ++標準ライブラリの文字列ストリームを使用できます。
stringstream ss(str);
int x;
ss >> x;
if(ss) { // <-- error handling
// use x
} else {
// not a number
}
整数を読み取ろうとしたときに数字以外が検出された場合、ストリームの状態は失敗するように設定されます。
C ++でのエラー処理とストリームの落とし穴については、ストリームの落とし穴を参照してください。
あなたはstringstreamのを使用することができます
int str2int (const string &str) {
stringstream ss(str);
int num;
ss >> num;
return num;
}
私はこれらの3つのリンクがそれを要約すると思います:
stringstreamおよびlexical_castソリューションは、字句キャストがstringstreamを使用しているのとほぼ同じです。
字句キャストのいくつかの特殊化は、異なるアプローチを使用します。詳細については、http://www.boost.org/doc/libs/release/boost/lexical_cast.hppを参照してください。整数と浮動小数点は、整数から文字列への変換に特化しています。
自分のニーズに合わせてlexical_castを特化して、高速にすることができます。これは、すべての関係者を満足させる、クリーンでシンプルな究極のソリューションです。
すでに述べた記事は、整数<->文字列を変換するさまざまな方法の比較を示しています。次のアプローチは意味があります:古いc-way、spirit.karma、fastformat、単純な単純ループ。
Lexical_castは、intから文字列への変換など、場合によっては問題ありません。
字句キャストを使用して文字列をintに変換することは、使用するプラットフォーム/コンパイラによってはatoiよりも10〜40倍遅いため、良い考えではありません。
Boost.Spirit.Karmaは、整数を文字列に変換するための最速のライブラリのようです。
ex.: generate(ptr_char, int_, integer_number);
上記の記事の基本的な単純なループは、文字列をintに変換する最も速い方法です。明らかに最も安全な方法ではありません。strtol()はより安全な解決策のようです。
int naive_char_2_int(const char *p) {
int x = 0;
bool neg = false;
if (*p == '-') {
neg = true;
++p;
}
while (*p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
if (neg) {
x = -x;
}
return x;
}
C ++文字列ライブラリツールキット(StrTk)は、次の解決策があります。
static const std::size_t digit_table_symbol_count = 256;
static const unsigned char digit_table[digit_table_symbol_count] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF - 0x07
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08 - 0x0F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x17
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18 - 0x1F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x27
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38 - 0x3F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40 - 0x47
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x48 - 0x4F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x50 - 0x57
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58 - 0x5F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x60 - 0x67
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x68 - 0x6F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x70 - 0x77
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78 - 0x7F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x87
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x88 - 0x8F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x97
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x98 - 0x9F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xA7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA8 - 0xAF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xB7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB8 - 0xBF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xC7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC8 - 0xCF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xD7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD8 - 0xDF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xE7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE8 - 0xEF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xF0 - 0xF7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 0xF8 - 0xFF
};
template<typename InputIterator, typename T>
inline bool string_to_signed_type_converter_impl_itr(InputIterator begin, InputIterator end, T& v)
{
if (0 == std::distance(begin,end))
return false;
v = 0;
InputIterator it = begin;
bool negative = false;
if ('+' == *it)
++it;
else if ('-' == *it)
{
++it;
negative = true;
}
if (end == it)
return false;
while(end != it)
{
const T digit = static_cast<T>(digit_table[static_cast<unsigned int>(*it++)]);
if (0xFF == digit)
return false;
v = (10 * v) + digit;
}
if (negative)
v *= -1;
return true;
}
InputIteratorは、unsigned char *、char *、またはstd :: stringイテレーターのいずれかであり、Tは、signed int、int、またはlongなどのsigned intであることが期待されています
v = (10 * v) + digit;
テキスト値がの文字列入力で不必要にオーバーフローしますINT_MIN
。表は単に対疑わしい価値があるdigit >= '0' && digit <= '9'
C ++ 17以降でstd::from_chars
は、ここに<charconv>
記載されているようにヘッダーから使用できます。
例えば:
#include <iostream>
#include <charconv>
#include <array>
int main()
{
char const * str = "42";
int value = 0;
std::from_chars_result result = std::from_chars(std::begin(str), std::end(str), value);
if(result.error == std::errc::invalid_argument)
{
std::cout << "Error, invalid format";
}
else if(result.error == std::errc::result_out_of_range)
{
std::cout << "Error, value too big for int range";
}
else
{
std::cout << "Success: " << result;
}
}
おまけとして、それは16進法のような他のベースも扱うことができます。
私はダンモールディングの答えが好きです。それにC ++スタイルを少し追加します。
#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>
int to_int(const std::string &s, int base = 0)
{
char *end;
errno = 0;
long result = std::strtol(s.c_str(), &end, base);
if (errno == ERANGE || result > INT_MAX || result < INT_MIN)
throw std::out_of_range("toint: string is out of range");
if (s.length() == 0 || *end != '\0')
throw std::invalid_argument("toint: invalid string");
return result;
}
暗黙的な変換により、std :: stringとconst char *の両方で機能します。また、すべてのto_int("0x7b")
and to_int("0173")
およびto_int("01111011", 2)
and to_int("0000007B", 16)
およびto_int("11120", 3)
and to_int("3L", 34);
は123を返すなど、基本変換にも役立ちます。
異なりstd::stoi
、それは前のC ++ 11で動作します。またstd::stoi
、boost::lexical_cast
とは異なり、stringstream
「123hohoho」のような奇妙な文字列に対して例外をスローします。
注意:この関数は、先頭のスペースは許容しますが、末尾のスペースは許容しません。つまり、例外to_int(" 123")
をto_int("123 ")
スローしながら123を返します。これがユースケースに受け入れられることを確認するか、コードを調整してください。
このような機能はSTLの一部になる可能性があります...
Stringをintに変換する3つの方法を知っています。
stoi(String to int)関数を使用するか、Stringstreamを使用するか、個々の変換を実行する3番目の方法であるコードを以下に示します。
最初の方法
std::string s1 = "4533";
std::string s2 = "3.010101";
std::string s3 = "31337 with some string";
int myint1 = std::stoi(s1);
int myint2 = std::stoi(s2);
int myint3 = std::stoi(s3);
std::cout << s1 <<"=" << myint1 << '\n';
std::cout << s2 <<"=" << myint2 << '\n';
std::cout << s3 <<"=" << myint3 << '\n';
2番目の方法
#include <string.h>
#include <sstream>
#include <iostream>
#include <cstring>
using namespace std;
int StringToInteger(string NumberAsString)
{
int NumberAsInteger;
stringstream ss;
ss << NumberAsString;
ss >> NumberAsInteger;
return NumberAsInteger;
}
int main()
{
string NumberAsString;
cin >> NumberAsString;
cout << StringToInteger(NumberAsString) << endl;
return 0;
}
3番目の方法-個別の変換ではありません
std::string str4 = "453";
int i = 0, in=0; // 453 as on
for ( i = 0; i < str4.length(); i++)
{
in = str4[i];
cout <<in-48 ;
}
例外を回避するため、特にダンの答えが好きです。組み込みシステム開発およびその他の低レベルシステム開発では、適切な例外フレームワークが利用できない場合があります。
有効な文字列の後の空白のチェックを追加しました...これらの3行
while (isspace(*end)) {
end++;
}
解析エラーのチェックも追加しました。
if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
これが完全な機能です。
#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2long (long &l, char const *s, int base = 0)
{
char *end = (char *)s;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE) && (l == LONG_MAX)) {
return OVERFLOW;
}
if ((errno == ERANGE) && (l == LONG_MIN)) {
return UNDERFLOW;
}
if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
while (isspace((unsigned char)*end)) {
end++;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
return SUCCESS;
}
" "
。 変換が発生しないときstrtol()
に設定errno
するように指定されていません。if (s == end) return INCONVERTIBLE;
変換なしを検出するために使用する方が良い。そして、 2)にif (*s == '\0' || *end != '\0')
単純化でき、目的を果たせません-それらは決して真実ではありません。if (*end)
|| l > LONG_MAX
|| l < LONG_MIN
この定義された方法を使用できます。
#define toInt(x) {atoi(x.c_str())};
また、StringからIntegerに変換する場合は、次のようにします。
int main()
{
string test = "46", test2 = "56";
int a = toInt(test);
int b = toInt(test2);
cout<<a+b<<endl;
}
出力は102になります。
atoi
、受け入れられstd::stoi()
たのような他の答えに照らして、「C ++の方法」のようには見えません。
私はこれが古い質問であることを知っていますが、何度も遭遇しましたが、今日まで、次の特性を持つ適切にテンプレート化されたソリューションをまだ見つけていません。
だから、これは私のテストストラップ付きの私のものです。内部でC関数strtoull / strtollを使用するため、常に最初に利用可能な最大の型に変換されます。次に、最大の型を使用していない場合は、追加の範囲チェックを実行して、型がオーバーフロー(アンダーフロー)していないことを確認します。このため、strtol / strtoulを適切に選択した場合よりもパフォーマンスが少し低下します。ただし、これはshort / charsでも機能し、私の知る限りでは、それを行う標準のライブラリ関数も存在しません。
楽しい; うまくいけば、誰かがそれが便利だと感じます。
#include <cstdlib>
#include <cerrno>
#include <limits>
#include <stdexcept>
#include <sstream>
static const int DefaultBase = 10;
template<typename T>
static inline T CstrtoxllWrapper(const char *str, int base = DefaultBase)
{
while (isspace(*str)) str++; // remove leading spaces; verify there's data
if (*str == '\0') { throw std::invalid_argument("str; no data"); } // nothing to convert
// NOTE: for some reason strtoull allows a negative sign, we don't; if
// converting to an unsigned then it must always be positive!
if (!std::numeric_limits<T>::is_signed && *str == '-')
{ throw std::invalid_argument("str; negative"); }
// reset errno and call fn (either strtoll or strtoull)
errno = 0;
char *ePtr;
T tmp = std::numeric_limits<T>::is_signed ? strtoll(str, &ePtr, base)
: strtoull(str, &ePtr, base);
// check for any C errors -- note these are range errors on T, which may
// still be out of the range of the actual type we're using; the caller
// may need to perform additional range checks.
if (errno != 0)
{
if (errno == ERANGE) { throw std::range_error("str; out of range"); }
else if (errno == EINVAL) { throw std::invalid_argument("str; EINVAL"); }
else { throw std::invalid_argument("str; unknown errno"); }
}
// verify everything converted -- extraneous spaces are allowed
if (ePtr != NULL)
{
while (isspace(*ePtr)) ePtr++;
if (*ePtr != '\0') { throw std::invalid_argument("str; bad data"); }
}
return tmp;
}
template<typename T>
T StringToSigned(const char *str, int base = DefaultBase)
{
static const long long max = std::numeric_limits<T>::max();
static const long long min = std::numeric_limits<T>::min();
long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type
// final range check -- only needed if not long long type; a smart compiler
// should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }
if (tmp < min || tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit signed range (";
if (sizeof(T) != 1) err << min << ".." << max;
else err << (int) min << ".." << (int) max; // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}
return tmp;
}
template<typename T>
T StringToUnsigned(const char *str, int base = DefaultBase)
{
static const unsigned long long max = std::numeric_limits<T>::max();
unsigned long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type
// final range check -- only needed if not long long type; a smart compiler
// should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }
if (tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit unsigned range (0..";
if (sizeof(T) != 1) err << max;
else err << (int) max; // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}
return tmp;
}
template<typename T>
inline T
StringToDecimal(const char *str, int base = DefaultBase)
{
return std::numeric_limits<T>::is_signed ? StringToSigned<T>(str, base)
: StringToUnsigned<T>(str, base);
}
template<typename T>
inline T
StringToDecimal(T &out_convertedVal, const char *str, int base = DefaultBase)
{
return out_convertedVal = StringToDecimal<T>(str, base);
}
/*============================== [ Test Strap ] ==============================*/
#include <inttypes.h>
#include <iostream>
static bool _g_anyFailed = false;
template<typename T>
void TestIt(const char *tName,
const char *s, int base,
bool successExpected = false, T expectedValue = 0)
{
#define FAIL(s) { _g_anyFailed = true; std::cout << s; }
T x;
std::cout << "converting<" << tName << ">b:" << base << " [" << s << "]";
try
{
StringToDecimal<T>(x, s, base);
// get here on success only
if (!successExpected)
{
FAIL(" -- TEST FAILED; SUCCESS NOT EXPECTED!" << std::endl);
}
else
{
std::cout << " -> ";
if (sizeof(T) != 1) std::cout << x;
else std::cout << (int) x; // don't print garbage chars
if (x != expectedValue)
{
FAIL("; FAILED (expected value:" << expectedValue << ")!");
}
std::cout << std::endl;
}
}
catch (std::exception &e)
{
if (successExpected)
{
FAIL( " -- TEST FAILED; EXPECTED SUCCESS!"
<< " (got:" << e.what() << ")" << std::endl);
}
else
{
std::cout << "; expected exception encounterd: [" << e.what() << "]" << std::endl;
}
}
}
#define TEST(t, s, ...) \
TestIt<t>(#t, s, __VA_ARGS__);
int main()
{
std::cout << "============ variable base tests ============" << std::endl;
TEST(int, "-0xF", 0, true, -0xF);
TEST(int, "+0xF", 0, true, 0xF);
TEST(int, "0xF", 0, true, 0xF);
TEST(int, "-010", 0, true, -010);
TEST(int, "+010", 0, true, 010);
TEST(int, "010", 0, true, 010);
TEST(int, "-10", 0, true, -10);
TEST(int, "+10", 0, true, 10);
TEST(int, "10", 0, true, 10);
std::cout << "============ base-10 tests ============" << std::endl;
TEST(int, "-010", 10, true, -10);
TEST(int, "+010", 10, true, 10);
TEST(int, "010", 10, true, 10);
TEST(int, "-10", 10, true, -10);
TEST(int, "+10", 10, true, 10);
TEST(int, "10", 10, true, 10);
TEST(int, "00010", 10, true, 10);
std::cout << "============ base-8 tests ============" << std::endl;
TEST(int, "777", 8, true, 0777);
TEST(int, "-0111 ", 8, true, -0111);
TEST(int, "+0010 ", 8, true, 010);
std::cout << "============ base-16 tests ============" << std::endl;
TEST(int, "DEAD", 16, true, 0xDEAD);
TEST(int, "-BEEF", 16, true, -0xBEEF);
TEST(int, "+C30", 16, true, 0xC30);
std::cout << "============ base-2 tests ============" << std::endl;
TEST(int, "-10011001", 2, true, -153);
TEST(int, "10011001", 2, true, 153);
std::cout << "============ irregular base tests ============" << std::endl;
TEST(int, "Z", 36, true, 35);
TEST(int, "ZZTOP", 36, true, 60457993);
TEST(int, "G", 17, true, 16);
TEST(int, "H", 17);
std::cout << "============ space deliminated tests ============" << std::endl;
TEST(int, "1337 ", 10, true, 1337);
TEST(int, " FEAD", 16, true, 0xFEAD);
TEST(int, " 0711 ", 0, true, 0711);
std::cout << "============ bad data tests ============" << std::endl;
TEST(int, "FEAD", 10);
TEST(int, "1234 asdfklj", 10);
TEST(int, "-0xF", 10);
TEST(int, "+0xF", 10);
TEST(int, "0xF", 10);
TEST(int, "-F", 10);
TEST(int, "+F", 10);
TEST(int, "12.4", 10);
TEST(int, "ABG", 16);
TEST(int, "10011002", 2);
std::cout << "============ int8_t range tests ============" << std::endl;
TEST(int8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(int8_t, "80", 16);
TEST(int8_t, "-80", 16, true, std::numeric_limits<int8_t>::min());
TEST(int8_t, "-81", 16);
TEST(int8_t, "FF", 16);
TEST(int8_t, "100", 16);
std::cout << "============ uint8_t range tests ============" << std::endl;
TEST(uint8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(uint8_t, "80", 16, true, std::numeric_limits<int8_t>::max()+1);
TEST(uint8_t, "-80", 16);
TEST(uint8_t, "-81", 16);
TEST(uint8_t, "FF", 16, true, std::numeric_limits<uint8_t>::max());
TEST(uint8_t, "100", 16);
std::cout << "============ int16_t range tests ============" << std::endl;
TEST(int16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(int16_t, "8000", 16);
TEST(int16_t, "-8000", 16, true, std::numeric_limits<int16_t>::min());
TEST(int16_t, "-8001", 16);
TEST(int16_t, "FFFF", 16);
TEST(int16_t, "10000", 16);
std::cout << "============ uint16_t range tests ============" << std::endl;
TEST(uint16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(uint16_t, "8000", 16, true, std::numeric_limits<int16_t>::max()+1);
TEST(uint16_t, "-8000", 16);
TEST(uint16_t, "-8001", 16);
TEST(uint16_t, "FFFF", 16, true, std::numeric_limits<uint16_t>::max());
TEST(uint16_t, "10000", 16);
std::cout << "============ int32_t range tests ============" << std::endl;
TEST(int32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(int32_t, "80000000", 16);
TEST(int32_t, "-80000000", 16, true, std::numeric_limits<int32_t>::min());
TEST(int32_t, "-80000001", 16);
TEST(int32_t, "FFFFFFFF", 16);
TEST(int32_t, "100000000", 16);
std::cout << "============ uint32_t range tests ============" << std::endl;
TEST(uint32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(uint32_t, "80000000", 16, true, std::numeric_limits<int32_t>::max()+1);
TEST(uint32_t, "-80000000", 16);
TEST(uint32_t, "-80000001", 16);
TEST(uint32_t, "FFFFFFFF", 16, true, std::numeric_limits<uint32_t>::max());
TEST(uint32_t, "100000000", 16);
std::cout << "============ int64_t range tests ============" << std::endl;
TEST(int64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(int64_t, "8000000000000000", 16);
TEST(int64_t, "-8000000000000000", 16, true, std::numeric_limits<int64_t>::min());
TEST(int64_t, "-8000000000000001", 16);
TEST(int64_t, "FFFFFFFFFFFFFFFF", 16);
TEST(int64_t, "10000000000000000", 16);
std::cout << "============ uint64_t range tests ============" << std::endl;
TEST(uint64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(uint64_t, "8000000000000000", 16, true, std::numeric_limits<int64_t>::max()+1);
TEST(uint64_t, "-8000000000000000", 16);
TEST(uint64_t, "-8000000000000001", 16);
TEST(uint64_t, "FFFFFFFFFFFFFFFF", 16, true, std::numeric_limits<uint64_t>::max());
TEST(uint64_t, "10000000000000000", 16);
std::cout << std::endl << std::endl
<< (_g_anyFailed ? "!! SOME TESTS FAILED !!" : "ALL TESTS PASSED")
<< std::endl;
return _g_anyFailed;
}
StringToDecimal
ユーザーランド方式です。これはオーバーロードされているため、次のように呼び出すことができます。
int a; a = StringToDecimal<int>("100");
またはこれ:
int a; StringToDecimal(a, "100");
私はint型を繰り返すのが嫌いなので、後者を好みます。これにより、「a」のタイプが変更されても、悪い結果が出ないことが保証されます。私はコンパイラがそれを次のように理解できることを願っています:
int a; a = StringToDecimal("100");
...しかし、C ++はテンプレートの戻り値の型を推定しないので、これは私が入手できる最高の方法です。
実装は非常に簡単です。
CstrtoxllWrapper
との両方strtoull
をラップstrtoll
し、テンプレートタイプの署名の有無に基づいて必要な方を呼び出し、追加の保証を提供します(たとえば、署名されていない場合、負の入力は許可されず、文字列全体が確実に変換されます)。
CstrtoxllWrapper
使用されるStringToSigned
とStringToUnsigned
、コンパイラが利用可能な最大タイプ(ロングロング/長い長い符号なし)と、これにより、最大限の変換を実行できます。次に、必要に応じて、StringToSigned
/ StringToUnsigned
は基になる型に対して最終的な範囲チェックを実行します。最後に、エンドポイントメソッドはStringToDecimal
、基になる型の署名の有無に基づいて、呼び出すStringTo *テンプレートメソッドを決定します。
ほとんどのジャンクはコンパイラーによって最適化できると思います。ほぼすべてがコンパイル時の確定的でなければなりません。この点についての解説は私にとって興味深いでしょう。
long long
代わりにintmax_t
?
if (ePtr != str)
。さらに、を使用isspace((unsigned char) *ePtr)
して、負の値を適切に処理します*ePtr
。
Cではint atoi (const char * str)
、
その内容を整数型として解釈するC文字列strを解析し、整数型の値として返されます。
atoi
質問でリンクしたように、私はそれを認識しています。問題は明らかにCについてではなく、C ++についてです。-1