CodeNebula
C++17stladvanced

std::from_chars / std::to_chars

C++17 · Practical Modern · Compiler flag: -std=c++17

Explanation

High-performance, locale-independent functions for converting between numeric values and character strings. They do not allocate memory, do not throw exceptions, and are significantly faster than `std::stoi`, `std::to_string`, or streams.

Real-World Scenario

Parse millions of numeric values from a CSV file in a high-frequency trading data loader.

Quick Snippet

snippet.cpp
#include <charconv>
#include <string_view>

// String to number
std::string_view sv = "314159";
int value = 0;
auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), value);

// Number to string
char buffer[32];
auto [end, ec2] = std::to_chars(buffer, buffer + sizeof(buffer), 42);
std::string_view result(buffer, end - buffer);  // "42"

Full Example

from_to_chars.cpp
// CodeNebula - C++17 Example: std::from_chars / std::to_chars
// Compile: g++ -std=c++17 -Wall -Wextra -o example from_to_chars.cpp

// Demonstrates std::to_chars and std::from_chars for fast, locale-independent
// number-to-string and string-to-number conversion. These avoid the overhead
// of streams and std::stoi/stod, and never allocate memory.

#include <iostream>
#include <charconv>
#include <array>
#include <string>
#include <system_error>
#include <cstring>

int main()
{
    // ------------------------------------------------------------------
    // 1. to_chars: integer to string
    // ------------------------------------------------------------------
    std::cout << "=== to_chars (integers) ===" << std::endl;
    std::array<char, 32> buf{};

    auto [ptr1, ec1] = std::to_chars(buf.data(), buf.data() + buf.size(), 42);
    std::cout << "  42       -> \"" << std::string(buf.data(), ptr1) << "\"" << std::endl;

    auto [ptr2, ec2] = std::to_chars(buf.data(), buf.data() + buf.size(), -12345);
    std::cout << "  -12345   -> \"" << std::string(buf.data(), ptr2) << "\"" << std::endl;

    // ------------------------------------------------------------------
    // 2. to_chars with different bases
    // ------------------------------------------------------------------
    std::cout << "\n=== to_chars (bases) ===" << std::endl;

    auto [ptr3, ec3] = std::to_chars(buf.data(), buf.data() + buf.size(), 255, 16);
    std::cout << "  255 hex  -> \"" << std::string(buf.data(), ptr3) << "\"" << std::endl;

    auto [ptr4, ec4] = std::to_chars(buf.data(), buf.data() + buf.size(), 255, 2);
    std::cout << "  255 bin  -> \"" << std::string(buf.data(), ptr4) << "\"" << std::endl;

    auto [ptr5, ec5] = std::to_chars(buf.data(), buf.data() + buf.size(), 255, 8);
    std::cout << "  255 oct  -> \"" << std::string(buf.data(), ptr5) << "\"" << std::endl;

    // ------------------------------------------------------------------
    // 3. from_chars: string to integer
    // ------------------------------------------------------------------
    std::cout << "\n=== from_chars (integers) ===" << std::endl;

    const char* s1 = "9876";
    int val1 = 0;
    auto [p1, e1] = std::from_chars(s1, s1 + std::strlen(s1), val1);
    std::cout << "  \"9876\"   -> " << val1 << std::endl;

    const char* s2 = "ff";
    int val2 = 0;
    auto [p2, e2] = std::from_chars(s2, s2 + std::strlen(s2), val2, 16);
    std::cout << "  \"ff\" hex -> " << val2 << std::endl;

    // ------------------------------------------------------------------
    // 4. from_chars stops at non-numeric characters
    // ------------------------------------------------------------------
    std::cout << "\n=== Partial Parsing ===" << std::endl;
    const char* s3 = "123abc";
    int val3 = 0;
    auto [p3, e3] = std::from_chars(s3, s3 + std::strlen(s3), val3);
    std::cout << "  \"123abc\" -> " << val3
              << " (stopped at '" << *p3 << "')" << std::endl;

    // ------------------------------------------------------------------
    // 5. Error handling
    // ------------------------------------------------------------------
    std::cout << "\n=== Error Handling ===" << std::endl;

    const char* s4 = "not_a_number";
    int val4 = -1;
    auto [p4, e4] = std::from_chars(s4, s4 + std::strlen(s4), val4);
    if (e4 == std::errc::invalid_argument)
        std::cout << "  \"not_a_number\" -> invalid_argument" << std::endl;

    // Buffer too small
    std::array<char, 2> tiny{};
    auto [p5, e5] = std::to_chars(tiny.data(), tiny.data() + tiny.size(), 99999);
    if (e5 == std::errc::value_too_large)
        std::cout << "  99999 in 2-char buf -> value_too_large" << std::endl;

    return 0;
}

/*
Expected output:

=== to_chars (integers) ===
  42       -> "42"
  -12345   -> "-12345"

=== to_chars (bases) ===
  255 hex  -> "ff"
  255 bin  -> "11111111"
  255 oct  -> "377"

=== from_chars (integers) ===
  "9876"   -> 9876
  "ff" hex -> 255

=== Partial Parsing ===
  "123abc" -> 123 (stopped at 'a')

=== Error Handling ===
  "not_a_number" -> invalid_argument
  99999 in 2-char buf -> value_too_large
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example from_to_chars.cpp