std::atoi,s...,std::atoll(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::atoi, std::atol, std::atoll β€” C++ Standard Library, bestie edition

okay so first things first: this whole page lives in the C++ Standard Library, and the manual name is std::atoi,s...,std::atoll(3). iconic, a little mysterious, but we move. πŸ¦‹


✨ NAME ✨

std::atoi, std::atol, std::atoll β€” yes bestie, the name is literally just std::atoi,std::atol,std::atoll. No extra lore, that's the whole thing. πŸ’–


🌸 Synopsis 🌸

so we're Defined in header <cstdlib> β€” write that down, it's the vibe check for includes:

int       atoi( const char* str );  (1)
long      atol( const char* str );  (2)
long long atoll( const char* str ); (3) (since C++11)

Note that (3) is since C++11, so if you're time-traveling to C++03, atoll is not invited to the party. πŸŽ€

Here's the tea: these functions interpret an integer value in a byte string pointed to by str. And the implied radix is always 10, like always always, no matter what cute little 0x you try to sneak in there. Not happening. πŸ™ˆ

They discard any whitespace characters until the first non-whitespace character is found, then take as many characters as possible to form a valid integer number representation, and convert them to an integer value. Very "eat what you can, leave the rest" of them. 😭

The valid integer value consists of the following parts:

  • (optional) plus or minus sign
  • numeric digits
⚠️ now the serious part, bestie, don't scroll past: if the value of the result cannot be represented, i.e. the converted value falls out of range of the corresponding return type, the behavior is undefined. Not "it clamps", not "it wraps nicely", undefined. πŸ’€ Do not test this at home.

πŸŽ€ Parameters πŸŽ€

  • str β€” pointer to the null-terminated byte string to be interpreted

that's it. one param. she's low maintenance. 🫢


πŸ’– Return value πŸ’–

On success you get the integer value corresponding to the contents of str. Slay.

And if no conversion can be performed, you get 0 returned. So 0 is both a legit answer and the "girl, I couldn't read that" answer. Ambiguous queen. πŸ‘‘


🌈 Possible implementation 🌈

copying this exactly because it's giving main character energy β€” a template, and everything:

template<typename T>
T atoi_impl(const char* str)
{
    while (std::isspace(static_cast<unsigned char>(*str)))
        ++str;

    bool negative = false;

    if (*str == '+')
        ++str;
    else if (*str == '-')
    {
        ++str;
        negative = true;
    }

    T result = 0;
    for (; std::isdigit(static_cast<unsigned char>(*str)); ++str)
    {
        int digit = *str - '0';
        result *= 10;
        result -= digit; // calculate in negatives to support INT_MIN, LONG_MIN,..
    }

    return negative ? result : -result;
}

int atoi(const char* str)
{
    return atoi_impl<int>(str);
}

long atol(const char* str)
{
    return atoi_impl<long>(str);
}

long long atoll(const char* str)
{
    return atoi_impl<long long>(str);
}

notice that little comment on result -= digit; β€” // calculate in negatives to support INT_MIN, LONG_MIN,.. β€” that's the whole trick, working in negatives so the minimum values don't fall off the edge. we stan one (1) clever line. 🧚

And for real-world tea: actual C++ library implementations fall back to C library implementations of atoi, atoil, and atoll (yes, atoil, that's what it says, keep it, don't @ me), which either implement it directly (as in MUSL libc) or delegate to strtol/strtoll (as in GNU libc). πŸ“


πŸ”₯ Example πŸ”₯

// Run this code

#include <cstdlib>
#include <iostream>

int main()
{
    const auto data =
    {
        "42",
        "0x2A", // treated as "0" and junk "x2A", not as hexadecimal
        "3.14159",
        "31337 with words",
        "words and 2",
        "-012345",
        "10000000000" // note: out of int32_t range
    };

    for (const char* s : data)
    {
        const int i{std::atoi(s)};
        std::cout << "std::atoi('" << s << "') is " << i << '\n';
        if (const long long ll{std::atoll(s)}; i != ll)
            std::cout << "std::atoll('" << s << "') is " << ll << '\n';
    }
}

look at that 0x2A comment bestie β€” treated as "0" and junk "x2A", not as hexadecimal. radix 10 said what it said. πŸ’…


⭐ Possible output ⭐

std::atoi('42') is 42
std::atoi('0x2A') is 0
std::atoi('3.14159') is 3
std::atoi('31337 with words') is 31337
std::atoi('words and 2') is 0
std::atoi('-012345') is -12345
std::atoi('10000000000') is 1410065408
std::atoll('10000000000') is 10000000000

see that 1410065408?? that's the 10000000000 being out of int32_t range doing its little undefined-behavior dance. and then atoll handles it fine because long long said "I got this". πŸ˜­πŸ’€


πŸ¦‹ See also πŸ¦‹

  • stoi, stol, stoll β€” converts a string to a signed integer β€” (function) (C++11)
  • stoul, stoull β€” converts a string to an unsigned integer β€” (function) (C++11)
  • strtol, strtoll β€” converts a byte string to an integer value β€” (function) (C++11)
  • strtoul, strtoull β€” converts a byte string to an unsigned integer value β€” (function) (C++11)
  • strtoimax, strtoumax β€” converts a byte string to std::intmax_t or std::uintmax_t β€” (function) (C++11)
  • from_chars β€” converts a character sequence to an integer or floating-point value β€” (function) (C++17)
  • C documentation for atoi, atol, atoll

and that's the page, bestie! 🫢 this one came from http://cppreference.com, dated 2024.06.10, and it's manual page std::atoi,s...,std::atoll(3). go forth and parse responsibly β€” and fr fr, watch that out-of-range thing. πŸ’œβœ¨

πŸ“¦ where this page comes from