2013-08-03 4 views
15

를 반환 내가이 다음 문자열 : 결과가변환 문자열은 잘못된 결과

iStart = 2147483647 

이 사람이 내 실수를 볼 수 있는가이다 그러나

sThis = "2154910440"; 

unsigned int iStart=atoi(sThis.c_str()); 

?

+0

합니다. atoi() 문서를 자세히 읽으면서 표지판이 무엇인지 살펴보십시오. – GreatBigBore

답변

28

atoi은 문자열을 int으로 변환합니다. 시스템에서 int은 32 비트이고 최대 값은 2147483647입니다. 변환하려는 값이이 범위를 벗어나므로 atoi의 반환 값은 정의되지 않습니다. 귀하의 구현은이 경우 int의 최대 값을 반환합니다.

대신에 atoll을 사용할 수 있습니다.이 길이는 long long을 반환하며 64 비트 이상이어야합니다. 또는 stoi/stol/stoll 패밀리의 함수 또는 unsigned counterparts을 사용할 수 있습니다.이 함수는 예외 범위의 범위를 벗어난 값 (및 유효하지 않은 값)에 대한 유용한 오류보고를 실제로 제공합니다.

개인적으로 나는 boost::lexical_cast을 좋아합니다. 다소 번거롭기는하지만 좀 더 일반적인 맥락에서 사용될 수 있습니다. 템플릿에서 사용할 수 있으며 전문화가 필요하지 않고 형식 인수를 전달할 수 있습니다.

+0

OP는 그가 C++ 11을 사용하고 있다고 말하지 않았습니다. –

+14

@Kyle_the_hacker : 글쎄, 2013 년입니다. 달리 말하지 않는 한, 제 대답으로 계속 추측하겠습니다. –

+3

@BenjaminLindley 어떤 종류의 현실을 무시합니다. –

7

atoi는 플랫폼에 최대 값이 2^31-1 인 부호있는 int를 반환합니다.

결과를 지정하는 데 아무런 문제가 없으며 반환 유형으로 제한됩니다.

C++ 스트림은 부호없는 int를 읽을 수 있습니다.

std::istringstream reader(sThis); 
unsigned int val; 
reader >> val; 
7

대신 부호없는 숫자 위해 설계 <cstdlib>에서 발견 std::strtoul을, 사용한다 더 큰 범위를 가지고있어 오류를보고 더 나은.

오류 처리를 위해 입력 및 예외에 std::string을 사용하려면 std::stoul을 사용하십시오. 다음과 같이 짧은, 매우 효율적인 구현은 다음과 같습니다

#include <string> 
#include <stdexcept> 
inline unsigned int stoui(const std::string& s) 
{ 
    unsigned long lresult = stoul(s, 0, 10); 
    unsigned int result = lresult; 
    if (result != lresult) throw std::out_of_range(); 
    return result; 
} 

이것은 istringstream보다 훨씬 빠를 것이다, 문화권, (행동 때문에 전혀 예상치 못한 변화 특이한 로케일에서 실행) 완전히 휴대용 및을 사용하여 세 번째 인수 인 경우 다른 숫자 기반을 지원하거나 0x0 접두사를 검색 할 수도 있습니다.

그러나 unsigned int은 반드시 값을 보유 할 정도로 크지 않으므로 unsigned long을 사용하면 위의 래퍼가 필요하지 않습니다.

+0

나는 strtoul이 더 이식성이 있다는 것에 동의한다. –

+0

내가 아는 한 unsigned long은 일부 플랫폼과 OS에서 unsigned int와 같지 않다. x86_64 아키텍처의 Linux에서는 크기가 달라야합니다. – Sergey

+0

@ Sergey : 예, 그렇기 때문에'strtoul'이 더 나은 선택입니다. 강제 변환 전후의 값을 'unsigned int'와 비교하여 값이 너무 큰지 여부를 확인할 수 있습니다. –

1

부호없는 int는 종종 C++의 32 비트 값이며 최대 값은 4,294,967,295입니다. 따라서 2,154,710,440은 부호없는 int로 표현 될 수 있습니다. 그러나 atoi는 부호가있는 int로 변환되며 최대 값은 2,147,483,647입니다. 따라서 문자열이 값 범위를 오버플로하여 답변이 잘못된 이유입니다. 문자열을 64 비트 이상인 긴 long으로 변환하는 atoll을 사용할 수 있습니다. 정수 크기는 C++에서 컴파일러에 따라 다릅니다. stdint.h 헤더 파일을 포함시킨 다음 uint32_t 또는 uint64_t 등을 사용하는 것이 좋습니다. 그러면 처리중인 크기를 알 수 있습니다.

1

항상 정확히을 수행하는 고유 한 기능을 작성할 수 있음을 잊지 마십시오.

이 코드는 -9223372036854775806 (2^63 + 1)과 9223372036854775807 (2^63-1) 사이의 숫자로 작동합니다. 이 같은

뭔가 :

long long int myAtoi (string str) { 
    long long int value = 0; 

    for (int i = 0; i < str.size(); i++) { 

     if (str[i] != '-') { 
      value *= 10; 
      value += (int) ((str[i]) - '0'); 
     } 
    } 


    if (str.size() > 0 && str[0] == '-') 
     return -value; 
    else 
     return value; 
} 
+0

주어진 바와 같이이 함수는 마이너스 기호를 너무 자유롭게 처리하며 -1033589를 반환하여 "----- 10 ---- 33 --- 5-8-9-"와 같은 문자열을 처리합니다. –

1

당신은 long int와 문자열을 변환 푸티 Atol를 사용할 수 있습니다. 자세한 내용은 Linux의 man atol을 참조하십시오.

#include <stdlib.h> 
long atol(const char *nptr); 
1

불행하게도 C++ 서명되지 않은 INT 구문 분석에 대한 임베디드 구현이 없으며이 정말 이상하다 프로토 타입.

#include <stdint.h> 
#include <sstream> 

inline unsigned int stoui(const std::string& s) 
{ 
    std::istringstream reader(s); 
    unsigned int val = 0; 
    reader >> val; 
    return val; 
} 

// This may be not the same as stoui on some platforms: 
inline uint32_t stoui32(const std::string& s) 
{ 
    std::istringstream reader(s); 
    uint32_t val = 0; 
    reader >> val; 
    return val; 
} 
+1

아무도 필요로하지 않았기 때문입니다. 'strtoul'은 유효한'unsigned int '값을 파싱하는데 완벽하게 잘 작동하며, 오버 플로우를 감지하기 위해서는 단지 하나의 여분의 비교가 필요합니다.간단히 말해서, 제공 한 오류 코드에서 깨진 (오류 검출에 완전히 부족한) 코드보다 훨씬 더 효율적입니다. –

+0

BTW, [기존 답변]을 회상하기 위해 downvoting (http://stackoverflow.com/a/18037886/103167). –

+0

@BenVoigt : 당신은 나쁜 해결책을 제안하고 있습니다. 불행히도 여기서는 코드 샘플을 넣을 수 없으므로 회신을 주요 질문으로 업데이트했습니다. – Sergey

0

atoistd::string 부호 INT int에하지 변환 : 여기

당신을 도울 수있는 코드입니다. 당신은 같은 것을 시도 할 수 있습니다 : - 부호 비트로 가장 높은 비트를 사용하여) 나는 그것이 atoi 함수 (에 문제가 있다고 생각 1. - 나는 당신의 결과가 2^31 것을 알 수

unsigned int iStart = *(unsigned*)(sThis.c_str());