본문 바로가기
프로그래밍 언어/C++

C++ 문자열 -> 숫자 변환 atoi vs stoi vs from_chars

by Jo_Wick 2025. 10. 1.
반응형

문자열 → 수 변환 3종 비교: atoi vs stoi vs from_chars

항목 atoi stoi from_chars
헤더 <cstdlib> <string> <charconv>
입력 형태 const char* (널종료) std::string 범위 (first, last) 포인터
진법 10 고정 2–36 지정 가능 정수: 2–36 지정 가능 / 부동소수: chars_format
실패 처리 0 반환(모호) invalid_argument, out_of_range 예외 std::errc 코드 반환(예외 없음)
범위 초과 정의 불명확 out_of_range 예외 ec = result_out_of_range
변환 끝 위치 없음 pos로 제공 result.ptr 로 제공
공백 스킵 일부 구현 의존 선행 공백 스킵함 스킵 안 함 (직접 다뤄야 함)
로케일 영향 가능 가능 영향 없음
힙 할당 없음 있을 수 있음 없음
표준/보급 C C++11 정수: C++17, 부동소수: C++17(광범위 구현은 C++20부터)**

요지: 고성능·미세 제어 → from_chars
안전/간편 → stoi
레거시 C 코드 호환 최소 기능 → atoi


std::from_chars 기본 형태

정수

#include <charconv> // from_chars
#include <system_error> // std::errc

std::from_chars_result r = std::from_chars(first, last, out_int, base);
// r.ptr: 파싱이 끝난 위치
// r.ec : std::errc{}(성공), invalid_argument, result_out_of_range

 

기본 특징

  • 선행 공백 미스킵(그대로 실패로 간주) → 필요하면 직접 isspace로 건너뛰기
  • +/- 부호 허용(정수)
  • 접두사(예: 0x)를 자동 인식하지 않음 → base=16이라도 "0xFF"는 실패. "FF"만 유효
  • 로케일 무시, 예외/할당 없음 → 매우 빠르고 예측 가능

부동소수

std::from_chars_result r =
  std::from_chars(first, last, out_double, std::chars_format::general);
// format: general / fixed / scientific / hex / (비트 OR 가능)
  • general: 일반 표기/지수 표기 모두 허용 (123.4, 1.23e2)
  • fixed: 고정소수점만
  • scientific: 지수 표기만
  • hex: C99 스타일 16진 부동소수(0x1.fp+2 등)

부동소수 오버로드는 표준상 C++17에 포함되지만, 실제 구현은 C++20부터 널리 안정적입니다.


실전 예제

1) 정수: 공백/접두사 직접 처리

#include <charconv>
#include <string>
#include <cctype>
#include <iostream>
using namespace std;

int main() {
    string s = "   1010xyz";
    const char* p = s.data();
    const char* end = p + s.size();

    // from_chars는 공백을 안 건너뛰므로 직접 처리
    while (p < end && isspace((unsigned char)*p)) ++p;

    int val = 0;
    auto r = from_chars(p, end, val, 2); // 2진수
    if (r.ec == errc{}) {
        cout << "val=" << val << ", next='" << string(r.ptr, end) << "'\n";
        // 출력: val=10, next="xyz"
    } else if (r.ec == errc::invalid_argument) {
        cout << "no digits\n";
    } else if (r.ec == errc::result_out_of_range) {
        cout << "overflow\n";
    }
}

2) 부동소수: 형식 제한

#include <charconv>
#include <string>
#include <iostream>
using namespace std;

int main() {
    string s = "3.14159e0 tail";
    double x;
    auto r = from_chars(s.data(), s.data() + s.size(), x, chars_format::general);
    if (r.ec == errc{}) {
        cout << x << " | rest: '" << string(r.ptr, s.data()+s.size()) << "'\n";
    }
}

3) 부분 문자열 범위 파싱(널 종료 불필요)

string line = "id=42;next";
auto begin = line.data() + 3;          // '4' 위치
auto stop  = line.data() + 5;          // '2' 다음 세미콜론 직전
int id;
auto r = from_chars(begin, stop, id, 10); // "42"만 대상으로 파싱

상황에 따라 써야하는 함수

  • 최고 성능/세밀 제어/예외 금지/로케일 독립: from_chars
    • 파서, 대용량 로그/파일 처리, 성능 민감 코드
  • 간편 + 안전(예외로 실패 구분): stoi
    • 사용자 입력 검증, 간단한 유틸, 진법 옵션 필요
  • 레거시/초간단: atoi
    • C 코드 유지보수, 실패 구분 불가 리스크 감수

공통 함정 & 팁

  • 공백: from_chars는 공백을 절대 안 건너뜀 → 직접 전처리
  • 접두사: from_chars 정수는 0x, 0b 등을 인지하지 않음
  • 범위: 오버플로는 result_out_of_range; 부분 파싱 시 result.ptr을 반드시 사용
  • 부동소수: 플랫폼 구현 상태 확인(C++20부터 보급), chars_format으로 허용 형식 명시
  • 로케일: 통일된 해석이 필요하면 from_chars가 확실 (, 소수점 등 로케일 영향 無)
반응형

댓글