签名十六进制字符串到long int函数

时间:2010-05-06 14:34:45

标签: c string hex twos-complement

我需要一个函数将32位或24位带符号(二进制补码)十六进制字符串转换为long int。需要在32位和64位机器上工作(无论长int的大小),无论机器是否是双补机,都需要工作。

SOLUTION:

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;
}

5 个答案:

答案 0 :(得分:5)

对于24位字符串:

解析十六进制字符串时,标准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位,因此您可以使用它。

E.g。

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;
}

答案 1 :(得分: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;
}

答案 2 :(得分:1)

这种比较错误:if (toupper (string[0]) == 'F')

您需要使用MSB集对任何值进行符号扩展,例如:

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

答案 3 :(得分:1)

有没有理由不能将strtol用于基数16?

答案 4 :(得分:0)

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

这将生成带有正确符号的数字。

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

这将始终产生积极的结果