Skip to content

/commands/cpp/convert-string-to-int

c++ convert string to int: std::stoi vs std::from_chars

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
C++
versions
C++11 (stoi), C++17 (from_chars)
os
any

std::stoi(s) converts an std::string to an int and throws std::invalid_argument if there is no number at the start, or std::out_of_range if the value does not fit. It skips leading white space and stops at the first character that is not part of the number, so "12abc" gives 12. std::from_chars (C++17, <charconv>) reports errors through a return value instead of exceptions and is the faster choice for parsers.

stoi and from_chars side by side

The example uses Clang 20 from the ziglang package on PyPI (with libc++), run through uv; cxx stands for it. On your machine, write g++ or clang++:

bash
cxx() { uv run -q --no-project --python 3.13 --with ziglang==0.15.1 python -m ziglang c++ -fno-color-diagnostics "$@"; }
cat > parse.cpp <<'EOF'
#include <charconv>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <system_error>

std::string with_stoi(const std::string& s) {
    try {
        std::size_t used = 0;
        int v = std::stoi(s, &used);
        return std::to_string(v) + (used == s.size() ? "" : " (stopped at " + std::to_string(used) + ")");
    } catch (const std::invalid_argument&) {
        return "invalid_argument";
    } catch (const std::out_of_range&) {
        return "out_of_range";
    }
}

std::string with_from_chars(const std::string& s) {
    int v = 0;
    auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), v);
    if (ec == std::errc::invalid_argument) return "invalid_argument";
    if (ec == std::errc::result_out_of_range) return "result_out_of_range";
    return std::to_string(v) + (ptr == s.data() + s.size() ? "" : " (trailing text)");
}

int main() {
    for (std::string s : {"42", "-17", "  8", "12abc", "abc", "", "3000000000", "+5"}) {
        std::cout << std::left << std::setw(13) << ('"' + s + '"')
                  << "stoi: " << std::setw(20) << with_stoi(s)
                  << "from_chars: " << with_from_chars(s) << '\n';
    }
    std::cout << "hex ff: " << std::stoi("ff", nullptr, 16) << '\n';
}
EOF
cxx -std=c++17 -Wall -Wextra parse.cpp -o parse && ./parse

Output

"42"         stoi: 42                  from_chars: 42
"-17"        stoi: -17                 from_chars: -17
"  8"        stoi: 8                   from_chars: invalid_argument
"12abc"      stoi: 12 (stopped at 2)   from_chars: 12 (trailing text)
"abc"        stoi: invalid_argument    from_chars: invalid_argument
""           stoi: invalid_argument    from_chars: invalid_argument
"3000000000" stoi: out_of_range        from_chars: result_out_of_range
"+5"         stoi: 5                   from_chars: invalid_argument
hex ff: 255

stoi accepts leading spaces and a + sign; from_chars accepts neither, by design: it parses exactly the characters you give it. Both stop at trailing text and report out-of-range values, but only the size_t* argument of stoi (or the returned pointer of from_chars) tells you that characters were left over.

Functions

FunctionHeaderOn error
std::stoi(s, &pos, base)<string>Throws invalid_argument or out_of_range
std::stol / stoll / stoul / stoull<string>Same, for long, long long and unsigned types
std::from_chars(first, last, value, base)<charconv>Returns {ptr, errc}; value unchanged on error (C++17)
std::istringstream iss(s); iss >> n<sstream>Sets failbit; slow, locale-dependent
std::atoi(s.c_str())<cstdlib>No error reporting; undefined behaviour on overflow

Pitfalls

  • Uncaught exceptions. An unhandled std::invalid_argument terminates the program with a message such as terminate called after throwing an instance of 'std::invalid_argument' (GCC); catch it around user input.
  • Wrong argument type. std::stoi takes a std::string (or std::wstring); passing a char or a std::string_view fails with no matching function for call to. Use std::from_chars for string_view and character buffers.
  • Unsigned parsing. std::stoul("-1") does not throw; it wraps around to the largest value, like C's strtoul.
  • Same pitfalls as C. stoi calls strtol internally; the C page on strtol explains base 0 and leading zeros.

Confirm it worked

Test empty input, letters, trailing text and a value just above INT_MAX (2147483648), and check that each is rejected the way you expect.

FAQ

Why does std::stoi("12abc") return 12 instead of failing?

stoi parses as many characters as it can and ignores the rest. Pass a pointer to a size_t as the second argument and compare it with the string length to reject trailing characters.

Which exceptions does std::stoi throw?

std::invalid_argument when no conversion could be performed, and std::out_of_range when the value does not fit in an int. Both derive from std::logic_error and std::exception.

Is std::from_chars faster than stoi?

Yes, usually. It does not allocate, throw or depend on the locale, which is why it is preferred in parsers and hot loops. It needs C++17 and <charconv>.

Sources