6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

c++における文字列から数値への変換 (stol, stodの使い方と注意点)

Last updated at Posted at 2020-08-24

はじめに

C++において文字列から数値に変換する方法は以下のようにいくつか存在する。

この中からどれを選んでも良いが、特にこだわりがなければ最後のstol, stodがもっとも簡単である。エラーケースのハンドリングなども扱いやすい。
この記事ではこの関数の使い方および注意点を紹介する。

基本的な使い方

まずはもっとも基本的な使い方から

sto.cpp
# 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;   // => "%"
    }
  }
}

リファレンス

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?