1 minute read

#include <cstdlib>
#include <cstdio>
#include <cerrno>

int main()
{
    char    *str = NULL;
    int     value = 0;

    str = "-123124";
    value = atoi( str );
    printf( "Function: atoi( \"%s\" ) = %d\n", str, value );

    str = "3336402735171707160320";
    value = atoi( str );
    printf( "Function: atoi( \"%s\" ) = %d\n", str, value );
    if (errno == ERANGE)
    {
        printf("Overflow condition occurred.\n");
    }

    return 0;
}

nil

문자열에서 integer, float로 캐스팅이 필요할 때, 주로 atoi, atof, strtol 등 CRT 함수를 사용한다. underflow, overflow가 발생하면 errno이 ERANGE로 세팅되고 최대값 혹은 최소값을 반환한다. 위 예제 코드는 MSDN 에서 가져왔다.

int stoi(const string& from)
{
    stringstream oss(from);

    int to;
    oss >> to;
    assert(!oss.fail() && !oss.bad() && oss.eof());
    if( oss.fail() || oss.bad() || !oss.eof() )
    {
        // 예외 처리
    }

    return to;
}

atoi를 STL에 있는 stringstream class를 사용해서 구현할 수 있다. “123d”와 같은 문자열을 문자열 스트림에 넣고 int로 출력하면 d 이전까지만 출력된다. 이 경우 스트링 문자열에 문자가 남아있게 된다. 이렇게 입력 문자열이 숫자로만 구성됐는지를 검사하려면 eof 플래그를 검사하면 된다. “d123” 같이 처음부터 출력하지 못하는 경우나 overflow나 underflow 경우에는 fail이나 bad 플래그가 세팅된다. 그래서 이 세 개의 플래그를 검사해서 예외 처리를 하면 된다. underflow, overflow 같은 경우는 atoi를 사용한 예제처럼 errno 값을 검사해서 확인할 수도 있다.

template<typename TO, typename FROM>
TO NumberStringCast( const FROM& from )
{
    stringstream ss;
    ss << from;

    TO result;
    ss >> result;

    assert(!ss.fail() && !ss.bad() && ss.eof());
    if( ss.fail() || ss.bad() || !ss.eof() )
    {
        // 예외 처리
    }

    return result;
}

int main()
{
    cout << NumberStringCast<int>("123") << endl;
    cout << NumberStringCast<string>(12.5f) << endl;
    cout << NumberStringCast<float>("123.3e10") << endl;

    return 0;
}

템플릿 클래스로 만들면 추가 코드 작성 없이 변환을 할 수 있다.

실행 속도는 당연히 CRT 함수인 atoi 시리즈가 당연히 빠르다. 속도에 민감하지 않는 부분이면 stringstream을 사용해서 편하게 캐스팅하는게 나을 것 같다. stringstream는 iostream 클래스를 상속받기 때문에 iostream처럼 다룰 수 있다는게 최고 장점이다. 이런게 있다는 것만 알고 사용하지 않았는데, 사용해보니 상당히 편하다.