代码之家  ›  专栏  ›  技术社区  ›  Cheetah

有符号十六进制字符串到long int函数

  •  0
  • Cheetah  · 技术社区  · 14 年前

    我需要一个函数将一个32位或24位有符号(以两个补码表示)的十六进制字符串转换成一个长整型。需要在32位和64位机器上工作(无论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;
    }
    
    5 回复  |  直到 14 年前
        1
  •  5
  •   CB Bailey    14 年前

    对于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位,因此您可以使用它。

    例如。

    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;
    }
    
        2
  •  1
  •   Aidan Cully    14 年前

    我们有一个 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;
    }
    
        3
  •  1
  •   Niall C.    14 年前

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

    您需要为任何带有msb集的值签名extend,因此类似于:

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

        4
  •  1
  •   Flad    14 年前

    你为什么不能用十六进制的strtol?

        5
  •  0
  •   Andrey    14 年前
      if (toupper (string[0]) == 'F')
      {
         return (result | 0xFF000000);
      }
    

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

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

    这将始终产生积极的结果