2010-05-06 8 views
0

32 비트 또는 24 비트 부호있는 (2의 보수) 16 진수 문자열을 long int로 변환하는 함수가 필요합니다. 32 비트 및 64 비트 머신 모두에서 작동해야하며 (long int의 크기와 상관없이) 머신이 2의 보수 머신인지 여부에 관계없이 작동합니다.부호있는 16 진수 문자열을 long int 함수

해결 방법 :

long int hex2li (char hexStr[], int signedHex) 
{ 
    int bits = strlen (hexStr) * 4; 

    char *pEnd; 
    long long int result = strtoll (hexStr, &pEnd, 16); 

    if (pEnd[0] == '\0') 
    { 
     if (signedHex) 
     { 
     if (result >= (1LL << (bits - 1))) result -= (1LL << bits); 
     } 

     return (long int) result; 
    } 

    return LONG_MIN; 
} 
+0

'8', '9', 'A', 'B', 'C', 'D'및 'E'로 시작하는 16 진수 문자열은 모두 음수 여야합니다. – caf

+0

FFFFFF는 24 비트 부호있는 16 진수와 32 비트 부호있는 16 진수로 서로 다른 의미를 가지므로 두 가지 유형의 문자열을 처리하는 단일 기능을 사용할 수 없습니다. 또한, non-two의 보완 기계에서 진정한 요구 사항을 다루고 있습니까? –

+0

'long '이 32 비트 인 컴퓨터에서 작업하는 것처럼 보입니다. FFFFFFFF가 32 비트 부호있는 값에서 표현할 수있는 최대 값보다 크기 때문에 2^31 -1이 가장 큰 표현 가능 값이므로 대신 사용됩니다. –

답변

5

-bit 문자열 :

표준 16 진수 문자열을 구문 분석 할 때 표준 strtol 함수는 0 -> 2^24 - 1 범위의 부호없는 값으로 읽습니다.

범위는 0 -> 2^23 - 1이지만 범위 2^23 -> 2^24 - 1-2^23 -> -1으로 매핑되어야하며 이는 다음과 같이 수행 할 수있는 간단한 빼기입니다.

if (result >= (1L << 23)) 
    result -= (1L << 24); 

는 뺄셈을 수행하기위한 서명 유형에서 전체 32 비트 부호없는 정수를 나타낼 수있는 중간 유형을 사용하는 것과 동일한 기술을 사용하여 32 비트 문자열을 변환합니다. long long int은 64 비트이므로이 값을 사용할 수 있습니다.

예.

long int ParseHexStr(const char *in, int bits) 
{ 
    char* endptr; 
    long long int result; 

    result = strtoll(in, &endptr, 16); 

    /* 
    ** TODO - error checking, e.g. check endptr != in 
    ** Also check for range errors, signalled by LLONG_MIN 
    ** LLONG_MAX and a errno == ERANGE. 
    */ 

    if (result >= (1LL << (bits - 1)) 
     result -= (1LL << bits); 

    return result; 
} 
+0

+1 멋지고 간단하며 길이가 32 비트보다 클 가능성을 배려합니다. –

+0

아키텍처가 실제로 2 중 보완법을 사용하지 않는 경우에도 작동해야합니다. 이것은 2의 보수 구조가 우세하다는 점을 감안하면 조금은 호기심이라고 인정합니다. –

+0

+1은 2의 보수가 아닌 아키텍처에서 작동합니다. –

0
if (toupper (string[0]) == 'F') 
    { 
    return (result | 0xFF000000); 
    } 

이 올바른 기호 번호를 생성합니다.

if (toupper (string[0]) == 'F') 
    { 
    return (~(result | 0xFF000000) + 1); 
    } 

이 항상 우리가 가지고있는 긍정적 인 결과

+0

첫 번째 숫자가 '8', ' 9 ','a ', ..'e '? 여전히 부정적이어야합니다. –

+0

'F'뿐만 아니라 MSB 세트 'if (result & 0x00800000)'로 다른 값을 확인해야합니다. –

+0

@Aidan Cully : "24bit 16 진수 문자열" – Andrey

1

을 생산하는 SIGN_EXTEND처럼 보이는, 매크로 : 그것은 >> 운영자에 의존

#define SIGN_EXTEND(X, SignBit, Type) \ 
    (((Type) ((X) << (8 * sizeof(Type) - (SignBit) - 1))) >> \ 
    (8 * sizeof(Type) - (SignBit) - 1)) 

부호 비트 인 경우 입력을 1 작성 세트. 이 같은 사용 문제에 대한

SIGN_EXTEND(0x89abcd, 23, int32_t); 

을, 당신은 사용할 수 있습니다

long int hex2li (char string[]) 
{ 
    char *pEnd; 
    long int result = SIGN_EXTEND(strtol (string, &pEnd, 16), 23, long int); 

    if(pEnd[0] == '\0') 
     return result; 
    return LONG_MIN; 
} 
+0

+1 문제를 올바르게 지정하는 일반 MACRO. 8 대신 CHAR_BIT를 사용하여 향상시킬 수 있지만 이는 단점입니다. –

1

이 비교가 잘못 : if (toupper (string[0]) == 'F')

당신은 MSB 어떤 값 로그인 확장해야합니다 세트, 그래서 뭔가 같은 : 24에 대한

if(strchr("89ABCDEF", toupper(string[0])) != NULL)

1

기수 16으로 strtol을 사용할 수없는 이유가 있습니까?

+0

그는 이미 있지만 긴 코드가 24 비트보다 크고 그는 6 자리 16 진수 표현을 가지고 있기 때문에 완전한 해결책은 아닙니다. –