C ++ 16 진 문자열을 부호있는 정수로 변환


135

C ++에서 16 진수 문자열을 부호있는 32 비트 정수로 변환하고 싶습니다.

예를 들어 16 진 문자열 "fffefffe"가 있습니다. 이진 표현은 11111111111111101111111111111110입니다. 서명 된 정수 표현은 -65538입니다.

C ++에서이 변환을 어떻게 수행합니까? 음수가 아닌 숫자에 대해서도 작동해야합니다. 예를 들어, 16 진수 문자열 "0000000A"는 2 진수로 00000000000000000000000000001010이고 10 진수로 10입니다.


2
노트. sizeof (int) == 4 인 시스템의 경우 -65538 만 제공
Martin York

3
@Martin York, 그는 언급하지 않았습니다 int. "32 비트 정수는"__int32 등 int32_t 일 또는 수
키릴 V. Lyadvinsky

답변:


230

사용하다 std::stringstream

unsigned int x;   
std::stringstream ss;
ss << std::hex << "fffefffe";
ss >> x;

다음 예제는 -65538결과로 생성 됩니다.

#include <sstream>
#include <iostream>

int main() {
    unsigned int x;   
    std::stringstream ss;
    ss << std::hex << "fffefffe";
    ss >> x;
    // output it as a signed type
    std::cout << static_cast<int>(x) << std::endl;
}

새로운 C ++ 11 표준에는 사용할 수있는 몇 가지 새로운 유틸리티 기능이 있습니다! 특히 "문자열 대 숫자"기능 군 ( http://en.cppreference.com/w/cpp/string/basic_string/stolhttp://en.cppreference.com/w/cpp/string/ basic_string / stoul ). 이들은 본질적으로 C의 문자열 대 숫자 변환 함수 주위의 얇은 래퍼이지만std::string

따라서 최신 코드에 대한 가장 간단한 답변은 다음과 같습니다.

std::string s = "0xfffefffe";
unsigned int x = std::stoul(s, nullptr, 16);

참고 : 아래는 원래 답변입니다. 편집 한 내용은 완전한 답변이 아닙니다. 기능 솔루션의 경우 코드를 :-) 줄 위에 붙여 넣으십시오.

이후 lexical_cast<>스트림 변환 의미론을 갖도록 정의 된 것으로 보인다 . 슬프게도 스트림은 "0x"표기법을 이해하지 못합니다. 그래서 boost::lexical_cast내 손으로 굴린 사람은 16 진수 줄을 잘 다루지 못합니다. 입력 스트림을 수동으로 16 진수로 설정하는 위의 솔루션은 잘 처리합니다.

Boost는이 작업 을 수행 할 수있는 몇 가지 사항 이 있으며 오류 검사 기능도 있습니다. 다음과 같이 사용할 수 있습니다.

try {
    unsigned int x = lexical_cast<int>("0x0badc0de");
} catch(bad_lexical_cast &) {
    // whatever you want to do...
}

부스트를 사용하고 싶지 않다면 오류 검사가없는 가벼운 어휘 캐스트 버전이 있습니다.

template<typename T2, typename T1>
inline T2 lexical_cast(const T1 &in) {
    T2 out;
    std::stringstream ss;
    ss << in;
    ss >> out;
    return out;
}

다음과 같이 사용할 수 있습니다.

// though this needs the 0x prefix so it knows it is hex
unsigned int x = lexical_cast<unsigned int>("0xdeadbeef"); 

1
이 방법을 사용하면 정수 값 152144602로 끝납니다
Clayton

@ jmanning2k, 예, 문자열에 std :: hex를 넣지 않으면 16 진수 문자열 (0x 접두사 포함)에서 boost 및 lexical_cast barf가 모두 이상합니다.
Evan Teran

1
@SteveWilkinson : " EDIT "로 시작하는 단락을 읽으십시오 . 사용법을 설명합니다std::hex
Evan Teran

1
대한 stringstream의 하나 확인해야합니다 ss.good() && ss.eof()확인 오류가 발생하지를 만들기 위해.
atoMerz

1
이 "stoul"내 논리를 저장
vincenzopalazzo

60

C 및 C ++ 모두에서 작동하는 메소드의 경우 표준 라이브러리 함수 strtol () 사용을 고려할 수 있습니다.

#include <cstdlib>
#include <iostream>
using namespace std;

int main() {
    string s = "abcd";
    char * p;
    long n = strtol( s.c_str(), & p, 16 );
    if ( * p != 0 ) { //my bad edit was here
        cout << "not a number" << endl;
    }
    else {
        cout << n << endl;
    }
}

2
사용 strtoul하지 않아야 strtol합니다. + overflowstrtol 을 사용할 때 있을 것 입니다. 함께 strtoul있을 것이다 오버 플로우 및 반환 값은 변환되지 않으며 long정확한 결과 (-65538)를 생성한다. 그래서 당신의 대답은 거의 옳습니다 :
Kirill V. Lyadvinsky

8
+1. 문자열 스트림을 사용하는 것보다 strtol (또는 strtoul)이 더 빠르기 때문입니다.
Kirill V. Lyadvinsky

27

Andy Buchanan은 C ++을 고수하는 한 당신을 좋아하지만 몇 가지 개조가 있습니다.

template <typename ElemT>
struct HexTo {
    ElemT value;
    operator ElemT() const {return value;}
    friend std::istream& operator>>(std::istream& in, HexTo& out) {
        in >> std::hex >> out.value;
        return in;
    }
};

같은

uint32_t value = boost::lexical_cast<HexTo<uint32_t> >("0x2a");

그렇게하면 int 유형 당 하나의 impl이 필요하지 않습니다.


1
나는 그 단계도 취했을 것이지만, 나는 꺾쇠 괄호의 확산을 제한하고 싶다는 것을 알았습니다. 이 경우 "복제 안 함"규칙을 어기는 것이 정당하다고 느꼈습니다. :-)
Andy J Buchanan

불행히도 필요하지만 훌륭하게 완료되었습니다. 개인 STL / 부스트 확장 / 수정 헤더에 추가되었습니다. 감사!
팀 실베스터

불행히도 이것은 서명되지 않은 변환에만 작동합니다. 따라서 0xFFFFFFFF를 -1로 변환 할 수 없습니다.
fmuecke

@fmuecke : 0xFFFFFFFF가 부호없는 정수 오버플로이기 때문에 정의되지 않은 동작입니다.
Billy ONeal

15

작업 예 strtoul는 다음과 같습니다.

#include <cstdlib>
#include <iostream>
using namespace std;

int main() { 
    string s = "fffefffe";
    char * p;
    long n = strtoul( s.c_str(), & p, 16 ); 
    if ( * p != 0 ) {  
        cout << "not a number" << endl;
    }    else {  
        cout << n << endl;
    }
}

strtol로 변환 string합니다 long. 내 컴퓨터에서 numeric_limits<long>::max()제공합니다 0x7fffffff. 분명히 그것은 0xfffefffe보다 큽니다 0x7fffffff. 따라서 원하는 값 대신에 strtol반환 MAX_LONG합니다. strtoul변환 stringunsigned long즉,이 경우 왜 오버 플로우 없습니다.

좋아, 변환 strtol하기 전에 입력 문자열을 32 비트 부호있는 정수로 간주하지 않습니다. 재미있는 샘플 strtol:

#include <cstdlib>
#include <iostream>
using namespace std;

int main() { 
    string s = "-0x10002";
    char * p;
    long n = strtol( s.c_str(), & p, 16 ); 
    if ( * p != 0 ) {  
        cout << "not a number" << endl;
    }    else {  
        cout << n << endl;
    }
}

위의 코드 -65538는 콘솔에서 인쇄 됩니다.


9

다른 곳에서 찾은 간단하고 효과적인 방법은 다음과 같습니다.

string hexString = "7FF";
int hexNumber;
sscanf(hexString.c_str(), "%x", &hexNumber);

값을 받으려면 부호없는 long integer / long integer를 사용하는 것이 좋습니다. 또 다른 메모, c_str () 함수는 std :: string을 const char *로 변환합니다.

따라서 const char *가 준비된 경우 아래에 표시된대로 변수 이름을 직접 사용하십시오. 또한 더 큰 16 진수에 대한 부호없는 긴 변수의 사용법도 보여줍니다. 문자열 대신 const char *를 사용하는 경우와 혼동하지 마십시오].

const char *hexString = "7FFEA5"; //Just to show the conversion of a bigger hex number
unsigned long hexNumber; //In case your hex number is going to be sufficiently big.
sscanf(hexString, "%x", &hexNumber);

이것은 완벽하게 잘 작동합니다 (필요에 따라 적절한 데이터 유형을 사용하는 경우).


6

오늘도 똑같은 문제가 있었는데, lexical_cast를 유지할 수 있도록 해결 방법은 다음과 같습니다.

typedef unsigned int    uint32;
typedef signed int      int32;

class uint32_from_hex   // For use with boost::lexical_cast
{
    uint32 value;
public:
    operator uint32() const { return value; }
    friend std::istream& operator>>( std::istream& in, uint32_from_hex& outValue )
    {
        in >> std::hex >> outValue.value;
    }
};

class int32_from_hex   // For use with boost::lexical_cast
{
    uint32 value;
public:
    operator int32() const { return static_cast<int32>( value ); }
    friend std::istream& operator>>( std::istream& in, int32_from_hex& outValue )
    {
        in >> std::hex >> outvalue.value;
    }
};

uint32 material0 = lexical_cast<uint32_from_hex>( "0x4ad" );
uint32 material1 = lexical_cast<uint32_from_hex>( "4ad" );
uint32 material2 = lexical_cast<uint32>( "1197" );

int32 materialX = lexical_cast<int32_from_hex>( "0xfffefffe" );
int32 materialY = lexical_cast<int32_from_hex>( "fffefffe" );
// etc...

(내가 덜 짜증나는 방법을 찾을 때이 페이지를 찾았습니다 :-)

건배


1
코드에 사소한 컴파일 오류가 있습니다. outvalue가 정의되지 않았습니다 (outValue 여야 함).
Gabi Davar

3

이것은 나를 위해 일했다 :

string string_test = "80123456";
unsigned long x;
signed long val;

std::stringstream ss;
ss << std::hex << string_test;
ss >> x;
// ss >> val;  // if I try this val = 0
val = (signed long)x;  // However, if I cast the unsigned result I get val = 0x80123456 

0

이 시도. 이 솔루션은 약간 위험합니다. 수표가 없습니다. 문자열에는 16 진수 값만 있어야하며 문자열 길이는 반환 유형 크기와 일치해야합니다. 그러나 추가 헤더가 필요하지 않습니다.

char hextob(char ch)
{
    if (ch >= '0' && ch <= '9') return ch - '0';
    if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
    if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
    return 0;
}
template<typename T>
T hextot(char* hex)
{
    T value = 0;
    for (size_t i = 0; i < sizeof(T)*2; ++i)
        value |= hextob(hex[i]) << (8*sizeof(T)-4*(i+1));
    return value;
};

용법:

int main()
{
    char str[4] = {'f','f','f','f'};
    std::cout << hextot<int16_t>(str)  << "\n";
}

참고 : 문자열의 길이는 2로 나눌 수 있어야합니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.