最終更新日時(UTC): 2025年12月03日 13時42分25秒
K10-K10 が更新

履歴 編集

function
<string>

# std::stoi(C++11)

    namespace std {
      int stoi(const std::string& str, std::size_t* idx = nullptr, int base = 10);  // (1)
      int stoi(const std::wstring& str, std::size_t* idx = nullptr, int base = 10); // (2)
    }

## 概要

文字列`str`を数値として読み取って、`int`型の値に変換する。

## 効果

パラメータ`str`が`string`型であれば`std::strtol(str.c_str(), &end, base)`、`wstring`型であれば`std::wcstol(str.c_str(), &end, base)`を呼び出して、その戻り値を返す。

パラメータ`idx`が非`nullptr`の場合、変換に使用されなかった要素のインデックス（`end - str.c_str()`）が格納される。

パラメータ`base`は、整数文字列`str`の基数を表す。デフォルトでは`10`進数として文字列を整数に変換する。基数は`2`から`36`(`36`含む)進数を指定できる。基数を`0`とした場合は、文字列のプレフィックスから基数が自動的に選択される。自動的な選択のルールは、以下のようになる：

- 先頭が`0`：`8`進数
- 先頭が`0x`もしくは`0X`：`16`進数

## 戻り値

変換して得られた数値が返される。

## 例外

- 数値への変換が行われなかった場合、`std::invalid_argument`が送出される。
- 以下の条件に合致した場合、`std::out_of_range`が送出される。
  - `std::strtol()`関数が`errno`変数に`ERANGE`を設定した場合 (C++14)
  - 結果が範囲外の値になった場合

## 備考

### errnoの扱い

- Visual C++ 11やGCC (libstdc++) 4.8.2では、この関数を呼び出すと`errno`の値が変更される。
- Clang (libc++) 3.3では、この関数の呼び出し前後で`errno`の値は変化しない。

### グローバルロケールの影響

この関数は、`setlocale()`関数により挙動が変化する。

`strtol()`関数での文字列先頭の空白を読み飛ばす処理に、`<cctype>`の`isspace()`関数が使用されるためである。

## 例

    #include <iostream>
    #include <string>

    int main()
    {
      // 10進法での変換
      {
        std::cout << "---- base = 10" << std::endl;

        int x = std::stoi("10"); // std::stoi("10", nullptr, 10);
        std::cout << x << std::endl;

        int xw = std::stoi(L"11"); // std::stoi(L"11", nullptr, 10);
        std::cout << xw << std::endl;
      }

      // 2進法での変換
      {
        std::cout << "---- base = 2" << std::endl;

        int x = std::stoi("1001", nullptr, 2);
        std::cout << x << std::endl;

        int xw = std::stoi(L"01001", nullptr, 2); // 先頭に0が付いていてもよい
        std::cout << xw << std::endl;
      }

      // 8進法での変換
      {
        std::cout << "---- base = 8" << std::endl;

        int x = std::stoi("10", nullptr, 8);
        std::cout << x << std::endl;

        int xw = std::stoi(L"10", nullptr, 8);
        std::cout << xw << std::endl;
      }

      // 16進法での変換
      {
        std::cout << "---- base = 16" << std::endl;

        int x = std::stoi("10", nullptr, 16);
        std::cout << x << std::endl;

        int xw = std::stoi(L"11", nullptr, 16);
        std::cout << xw << std::endl;
      }

      // 16進法での変換（プレフィックス付き）
      {
        int x = std::stoi("0x20", nullptr, 16);
        std::cout << x << std::endl;

        int xw = std::stoi(L"0x21", nullptr, 16);
        std::cout << xw << std::endl;
      }

      // base = 0による10進法・8進法・16進法の自動判別
      {
        std::cout << "---- base = 0" << std::endl;

        std::cout << std::stoi("100", nullptr, 0) << std::endl;
        std::cout << std::stoi("0100", nullptr, 0) << std::endl;
        std::cout << std::stoi("0x100", nullptr, 0) << std::endl;

        std::cout << std::stoi(L"100", nullptr, 0) << std::endl;
        std::cout << std::stoi(L"0100", nullptr, 0) << std::endl;
        std::cout << std::stoi(L"0x100", nullptr, 0) << std::endl;
      }

      // 2番目の仮引数の使用例
      {
        std::cout << "---- use of idx parameter" << std::endl;

        std::string s = "30%";
        std::size_t i;
        int x = std::stoi(s, &i);
        std::cout << x << ' ' << s[i] << std::endl;

        std::wstring ws = L"31%";
        std::size_t wi;
        int xw = std::stoi(ws, &wi);
        std::cout << xw << ' ' << wi << std::endl;
      }

      // 文字列先頭に空白がある場合
      {
        std::cout << "---- space character before number" << std::endl;
        std::cout << std::stoi("    -1") << std::endl;
        std::cout << std::stoi(L"    -2") << std::endl;
      }
    }

### 出力

    ---- base = 10
    10
    11
    ---- base = 2
    9
    9
    ---- base = 8
    8
    8
    ---- base = 16
    16
    17
    32
    33
    ---- base = 0
    100
    64
    256
    100
    64
    256
    ---- use of idx parameter
    30 %
    31 2
    ---- space character before number
    -1
    -2

## 実装例

    int stoi(const std::string& str, std::size_t* idx = nullptr, int base = 10) {
      const char* p = str.c_str();
      char* end;
      errno = 0;
      long x = std::strtol(p, &end, base);
      if (p == end) {
        throw std::invalid_argument("stoi");
      }
      if (errno == ERANGE || x < INT_MIN || x > INT_MAX) {
        throw std::out_of_range("stoi");
      }
      if (idx != nullptr) {
        *idx = static_cast<std::size_t>(end - p);
      }
      return static_cast<int>(x);
    }

    int stoi(const std::wstring& str, std::size_t* idx = nullptr, int base = 10) {
      const wchar_t* p = str.c_str();
      wchar_t* end;
      errno = 0;
      long x = std::wcstol(p, &end, base);
      if (p == end) {
        throw std::invalid_argument("stoi");
      }
      if (errno == ERANGE || x < INT_MIN || x > INT_MAX) {
        throw std::out_of_range("stoi");
      }
      if (idx != nullptr) {
        *idx = static_cast<std::size_t>(end - p);
      }
      return static_cast<int>(x);
    }

## バージョン

### 言語

- C++11

### 処理系

- Clang: ?
- GCC: ?
- ICC: ?
- Visual C++: 2010 ✅, 2012 ✅, 2013 ✅

## 関連リンク

### C標準ライブラリに由来する関数

- `atoi`: `stoi`は`atoi`を`std::string`および`std::wstring`に対応させたものと見なせる。
- `strtol`, `wcstol`: `stoi`は`strtol`および`wcstol`をそれぞれ`std::string`と`std::wstring`に対応させ、戻り値の型を`int`に変更したものと見なせる。

### ファミリー

- (`stoi`: この関数自身)
- `stol`: 戻り値の型が`long`となったもの。
- `stoll`: 戻り値の型が`long long`となったもの。
- `stoul`: 戻り値の型が`unsigned long`となったもの。
- `stoull`: 戻り値の型が`unsigned long long`となったもの。
- `stof`: 戻り値の型が`float`となったもの。
- `stod`: 戻り値の型が`double`となったもの。
- `stold`: 戻り値の型が`long double`となったもの。

### ロケール依存しない高速な変換関数

- `from_chars`

## 参照

- N2408 Simple Numeric Access Revision 2
- LWG Issue 2009. Reporting out-of-bound values on numeric string conversions