16 진수 문자열 (char [])을 int로 변환 하시겠습니까?


82

"0x1800785"와 같은 값을 포함하는 char []가 있지만 값을 제공하려는 함수에는 int가 필요합니다. 어떻게 이것을 int로 변환 할 수 있습니까? 주변을 수색했지만 답을 찾을 수 없습니다. 감사.


답변:


207

시도해 보셨습니까 strtol()?

strtol-문자열을 긴 정수로 변환

예:

const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);

경우에 숫자의 문자열 표현은 시작 0x접두사, 하나는 있어야 기지로 0을 사용한다 :

const char *hexstring = "0xabcdef0";
int number = (int)strtol(hexstring, NULL, 0);

(16과 같은 명시 적 기반을 지정하는 것도 가능하지만 중복성을 도입하는 것은 권장하지 않습니다.)


4
hexstring은 항상 도입되면 "0x"그냥 사용해야하는 문제에 주어진 0대신 16.
Jens Gustedt 2012

16
@KelvinHu cplusplus.com을 믿지 마세요, 쓰레기입니다. 있으면 cppreference.com으로 이동 하십시오 .

1
@KelvinHu 기술적으로 부정확하거나 느슨하게 표현 된 많은 정보가 해당 사이트에 있으며 SO 주변에서 C ++ 프로그래머를 보면 모두 이러한 이유로이 정보에 의존하지 않는 것이 좋습니다.

1
@ H2CO3 좋아, 나는 C ++를 처음 접했기 때문에 이것을 google로 검색하면 cplusplus.com 이 맨 앞에 위치합니다. 귀하의 정보에 감사드립니다.
Kelvin Hu

3
참고 로 매우 큰 헥스를 다룰 때 좋은 strtol유형 long을 제공합니다 . 더 큰 헥스에 strtoll대한 유형 long long에 사용하십시오 .
Steven Lu

20

또는 자체 구현을 원할 경우이 빠른 함수를 예로 작성했습니다.

/**
 * hex2int
 * take a hex string and convert it to a 32bit number (max 8 hex digits)
 */
uint32_t hex2int(char *hex) {
    uint32_t val = 0;
    while (*hex) {
        // get current character then increment
        uint8_t byte = *hex++; 
        // transform hex character to the 4bit equivalent number, using the ascii table indexes
        if (byte >= '0' && byte <= '9') byte = byte - '0';
        else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
        else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;    
        // shift 4 to make space for new digit, and add the 4 bits of the new digit 
        val = (val << 4) | (byte & 0xF);
    }
    return val;
}

1
마이크로 컨트롤러와 같이 리소스가 제한된 플랫폼에 매우 유용합니다.
Mubin Icyer

19

다음과 같은 것이 유용 할 수 있습니다.

char str[] = "0x1800785";
int num;

sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num); 

남자 sscanf 읽기


1
이로 인해 정의되지 않은 동작이 발생 %x하고 unsigned int. 그리고 UINT_MAX그것을
MM

10

문자열이라고 가정하면 strtol은 어떻습니까?


나는 원래 strtol 대신 strtod (-> double)에 연결했습니다. 내가 편집하는 동안 누군가 본 것 같아요.
James McLaughlin 2012

글쎄요, 그건 실수가 아닙니다 ... 컴파일러는 int. +1, btw.

저는 double이 32 비트 정수가 할 수있는 모든 가능한 값을 저장할 수 있다고 생각하지 않습니다 (실제로 이것이 사실인지 아는 사람이 있습니까? 저는 부동 소수점 숫자 표현에 대해 100 %가 아닙니다.)
James McLaughlin

4
@JamesMcLaughlin 할 수 있습니다. 64 비트 IEEE double은 약 2 ^ 53의 정수 정확도를 갖습니다.

세부 사항, "64 비트 IEEE double은 약 2 ^ 53의 정수 정확도를가집니다." 그리고 기호 비트. 그래서 그것은 int54_tuint53_t.
chux-모니카 복원

5

strtol최상위 답변이 제안한 것처럼 libc를 사용할 수 있으면 사용하십시오 . 그러나 사용자 정의 항목을 좋아하거나 libc가없는 마이크로 컨트롤러를 사용하는 경우 복잡한 분기없이 약간 최적화 된 버전을 원할 수 있습니다.

#include <inttypes.h>


/**
 * xtou64
 * Take a hex string and convert it to a 64bit number (max 16 hex digits).
 * The string must only contain digits and valid hex characters.
 */
uint64_t xtou64(const char *str)
{
    uint64_t res = 0;
    char c;

    while ((c = *str++)) {
        char v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8);
        res = (res << 4) | (uint64_t) v;
    }

    return res;
} 

비트 이동 마법은 다음과 같이 요약됩니다. 마지막 4 비트 만 사용하고 숫자가 아닌 경우 9를 더합니다.


기회가된다면 "v ="라인이 어떻게 작동하는지 좀 더 자세히 설명해 주시겠습니까? 다음과 같이 내 목적을 위해 함수를 구현했습니다.unsigned long long int hextou64(char *str) { unsigned long long int n = 0; char c, v; for (unsigned char i = 0; i < 16; i++) { c = *(str + i); v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8); n = (n << 4) | (unsigned long long int)v; } return n; }
iamoumuamua

그래도 함께 할 수 있을지 한 번 볼게요 ^^ 꽤 까다로운 것 같아요. 전제 : '0'- '9'는 모두 '0011 ????'으로 시작합니다. 바이너리로. 'A'- 'F'는 모두 '0100 ????'으로 시작합니다. 바이너리로. 이 정보를 사용하여 분기를 방지 할 수 있습니다. (c & 0xF) → 마지막 4 비트 만 값을 포함합니다. 이것은 이미 '0'- '9'에 대한 올바른 값입니다. 'A'- 'F'의 경우 올바른 값을 얻으려면 소수점 9를 추가해야합니다. (예를 들어 16 진수 C는 0011로 끝납니다. 이는 3입니다. 그러나 12를 원합니다. 따라서 우리는 9를 더해야합니다. (c >> 6) | ((c >> 3) & 0x8)→ 문자의 경우 9, 소수의 경우 0으로 평가됩니다. 예, 상당히 해키 :)
LimeRed

3

아래 코드 블록을 시도해보십시오.

char *p = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);

printf("value x: %x - %d", intVal, intVal);

출력은 다음과 같습니다.

value x: 820 - 2080

3

그래서 잠시 검색하고 strtol이 상당히 느리다는 것을 알게 된 후, 저는 제 자신의 함수를 코딩했습니다. 문자의 대문자에서만 작동하지만 소문자 기능을 추가하는 것은 문제가되지 않습니다.

int hexToInt(PCHAR _hex, int offset = 0, int size = 6)
{
    int _result = 0;
    DWORD _resultPtr = reinterpret_cast<DWORD>(&_result);
    for(int i=0;i<size;i+=2)
    {
        int _multiplierFirstValue = 0, _addonSecondValue = 0;

        char _firstChar = _hex[offset + i];
        if(_firstChar >= 0x30 && _firstChar <= 0x39)
            _multiplierFirstValue = _firstChar - 0x30;
        else if(_firstChar >= 0x41 && _firstChar <= 0x46)
            _multiplierFirstValue = 10 + (_firstChar - 0x41);

        char _secndChar = _hex[offset + i + 1];
        if(_secndChar >= 0x30 && _secndChar <= 0x39)
            _addonSecondValue = _secndChar - 0x30;
        else if(_secndChar >= 0x41 && _secndChar <= 0x46)
            _addonSecondValue = 10 + (_secndChar - 0x41);

        *(BYTE *)(_resultPtr + (size / 2) - (i / 2) - 1) = (BYTE)(_multiplierFirstValue * 16 + _addonSecondValue);
    }
    return _result;
}

용법:

char *someHex = "#CCFF00FF";
int hexDevalue = hexToInt(someHex, 1, 8);

변환하려는 16 진수가 오프셋 1에서 시작하기 때문에 1이고 16 진수 길이이기 때문에 8입니다.

Speedtest (1.000.000 호출) :

strtol ~ 0.4400s
hexToInt ~ 0.1100s

2

빠르고 더러운 솔루션 :

// makes a number from two ascii hexa characters
int ahex2int(char a, char b){

    a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
    b = (b <= '9') ? b - '0' : (b & 0x7) + 9;

    return (a << 4) + b;
}

입력이 정확하고 유효성 검사가 포함되지 않았는지 확인해야합니다 (C라고 말할 수 있음). 다행스럽게도 매우 컴팩트합니다. 'A'에서 'F'로, 'a'에서 'f'로 작동합니다.

접근 방식은 ASCII 테이블에서 알파벳 문자의 위치에 의존합니다. 예를 들어 Wikipedia ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png ) 를 살펴 보겠습니다 . 간단히 말해서 숫자는 문자 아래에 있으므로 숫자 (0 ~ 9)는 0에 대한 코드를 빼면 쉽게 변환됩니다. 알파벳 문자 (A ~ F)는 마지막 3 비트 이외의 0으로 읽히고 (효과적으로 대문자 또는 소문자로 작동하도록 함) 1을 빼고 (비트 마스킹 후 알파벳이 위치 1에서 시작하기 때문에) 10을 더합니다 ( A에서 F는 16 진수 코드에서 10 번째에서 15 번째 값을 나타 내기 때문입니다. 마지막으로 인코딩 된 숫자의 하단 및 상단 니블을 형성하는 두 자리를 결합해야합니다.

여기에서는 동일한 접근 방식을 사용합니다 (사소한 변형 포함).

#include <stdio.h>

// takes a null-terminated string of hexa characters and tries to 
// convert it to numbers
long ahex2num(unsigned char *in){

    unsigned char *pin = in; // lets use pointer to loop through the string
    long out = 0;  // here we accumulate the result

    while(*pin != 0){
        out <<= 4; // we have one more input character, so 
                   // we shift the accumulated interim-result one order up
        out +=  (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9; // add the new nibble
        pin++; // go ahead
    }

    return out;
}

// main function will test our conversion fn
int main(void) {

    unsigned char str[] = "1800785";  // no 0x prefix, please
    long num;

    num = ahex2num(str);  // call the function

    printf("Input: %s\n",str);  // print input string
    printf("Output: %x\n",num);  // print the converted number back as hexa
    printf("Check: %ld = %ld \n",num,0x1800785);  // check the numeric values matches

    return 0;
}

1
답변을 게시 한 후 나는 @LimeRed의 게시물을 놓쳤다는 것을 알았습니다. 매우 귀엽습니다
Simon

1

char 배열을 포함하는 16 진수를 추가 라이브러리가 필요없는 정수로 직접 변환하는 함수입니다.

int hexadecimal2int(char *hdec) {
    int finalval = 0;
    while (*hdec) {
        
        int onebyte = *hdec++; 
        
        if (onebyte >= '0' && onebyte <= '9'){onebyte = onebyte - '0';}
        else if (onebyte >= 'a' && onebyte <='f') {onebyte = onebyte - 'a' + 10;}
        else if (onebyte >= 'A' && onebyte <='F') {onebyte = onebyte - 'A' + 10;}  
        
        finalval = (finalval << 4) | (onebyte & 0xF);
    }
    finalval = finalval - 524288;
    return finalval;
}

0

나는 사용하지 않고 16 진수 / 10 진수 변환을 위해 librairy를 만들었습니다 stdio.h. 사용하기 매우 간단합니다.

unsigned hexdec (const char *hex, const int s_hex);

첫 번째 변환 전에 다음을 사용하여 변환에 사용되는 배열을 초기화하십시오.

void init_hexdec ();

여기 github의 링크 : https://github.com/kevmuret/libhex/


0

나는 비슷한 일을했는데, 그것이 실제로 나를 위해 일하는 데 도움이 될 것이라고 생각합니다.

int main(){ int co[8],i;char ch[8];printf("please enter the string:");scanf("%s",ch);for(i=0;i<=7;i++){if((ch[i]>='A')&&(ch[i]<='F')){co[i]=(unsigned int)ch[i]-'A'+10;}else if((ch[i]>='0')&&(ch[i]<='9')){co[i]=(unsigned int)ch[i]-'0'+0;}}

여기에서는 8 자 문자열 만 가져 왔습니다. u가 동일한 16 진수 값을 제공하기 위해 'a'에 대한 유사한 논리를 'f'에 추가 할 수 있기를 원한다면, 나는 그것을 필요로하지 않았기 때문에 그렇게하지 않았습니다.


-1

xtoi (stdlib.h)를 사용하십시오. 문자열에는 처음 두 인덱스로 "0x"가 있으므로 xtoi & val [2]를 전송하여 val [0] 및 val [1]을 잘라냅니다.

xtoi( &val[2] );


xtoi표준 기능이 아님
MM

-5

나는 이것이 정말 오래되었다는 것을 알고 있지만 솔루션이 너무 복잡해 보였다고 생각합니다. VB에서 이것을 시도하십시오.

Public Function HexToInt(sHEX as String) as long
Dim iLen as Integer
Dim i as Integer 
Dim SumValue as Long 
Dim iVal as long
Dim AscVal as long

    iLen = Len(sHEX)
    For i = 1 to Len(sHEX)
      AscVal = Asc(UCase(Mid$(sHEX, i,  1)))
      If AscVal >= 48 And AscVal  <= 57 Then
        iVal  = AscVal - 48
      ElseIf AscVal >= 65 And AscVal <= 70 Then
        iVal = AscVal - 55
      End If 
      SumValue = SumValue + iVal * 16 ^ (iLen- i)
    Next i 
    HexToInt  = SumValue
End Function 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.