はじめに
C++において文字列から数値に変換する方法は以下のようにいくつか存在する。
- 関数
atol
,atof
を使う -
strtol
,strtof
関数を使う -
stringstream
を使う -
stol
,stod
関数を使う (C++11)
この中からどれを選んでも良いが、特にこだわりがなければ最後のstol
, stod
がもっとも簡単である。エラーケースのハンドリングなども扱いやすい。
この記事ではこの関数の使い方および注意点を紹介する。
基本的な使い方
まずはもっとも基本的な使い方から
# include <iostream>
# include <string>
int main() {
std::cout << std::stol("1234") << std::endl; // => 1234
}
文字列を引数にして、stolを呼ぶだけ。これでlongに変換できる。doubleに変換したい場合は、stod
を呼ぶ。
std::cout << std::stod("123.456") << std::endl; // => 123.456
当然ながら、文字列の先頭に"+"や"-"などの符号がついていても問題ない。
std::cout << std::stol("-1234") << std::endl; // => -1234
std::cout << std::stol("+1234") << std::endl; // => 1234
注意点
変換できない文字列が与えられた場合、std::invalid_argument
が発生する。
long l = std::stol("abc"); // => throws an exception (std::invalid_argument)
しかし、途中まで数値として解釈できる場合は例外が発生しない。
std::cout << std::stol("3abc") << std::endl; // => 3
範囲外の大きな数値を指定すると、std::out_of_range
が発生。
ただし、stoull
などの関数でunsignedの変数に変換する場所でマイナスつきの文字列を指定しても、例外は発生せず変換できる。
// std::cout << std::stoull("18446744073709551616") << std::endl; // 2^64-1 より大きい値を指定すると std::out_of_range が発生
std::cout << std::stoull("18446744073709551615") << std::endl; // 2^64-1 は変換可能
// std::cout << std::stoll("18446744073709551615") << std::endl; // std::out_of_range. 2^64-1 はlongでは表せない。
std::cout << std::stoul("-1") << std::endl; // => 18446744073709551615 (例外を投げてくれない)
}
引数で何も指定しない場合、デフォルトで10進数として解釈される。基数は第3引数で指定することができる。
{
std::cout << std::stol("0xFF") << std::endl; // => 0 (デフォルトでは10進数として解釈される)
std::cout << std::stol("0xFF", nullptr, 16) << std::endl; // => 255 (16進数として解釈される)
std::cout << std::stol("01101", nullptr, 2) << std::endl; // => 13 (2進数として解釈される)
}
第3引数に0
を指定することにより、8進数、16進数の表記を解釈できるようになる。
ただし、2進数表記0b...
は解釈できない。
{ // 第3引数に0を指定すると、"0...", "0x..."の記法を解釈してくれる。ただし"0b..."の表記は解読してくれないので注意。
std::cout << std::stol("100", nullptr, 0) << std::endl; // => 100
std::cout << std::stol("0b100", nullptr, 0) << std::endl; // => 0 (binaryの判定はできない)
std::cout << std::stol("0100", nullptr, 0) << std::endl; // => 64
std::cout << std::stol("0x100", nullptr, 0) << std::endl; // => 256
}
数値として解釈できない文字が存在する場合、その情報は第二引数に入る。
全文字列が数値として変換されたかチェックするためには、以下のようにs.size() == idx
のチェックが必要。
{ // usage of the second argument
size_t idx = 0;
std::string s = "30";
std::stol(s, &idx);
assert(s.size() == idx); // idx == s.size() == 2
s = "30%";
std::stol(s, &idx); // idx => 2
if (idx != s.size()) {
std::cout << s[idx] << std::endl; // => "%"
}
}
}