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

发布于 2024-08-31 12:25:46 字数 544 浏览 5 评论 0原文

我需要一个函数将 32 位或 24 位有符号(二进制补码)十六进制字符串转换为 long int。需要在 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;
}

I need a function to convert a 32bit or 24bit signed (in two's complement) hexadecimal string into a long int. Needs to work on both 32bit and 64bit machines (regardless of the size of long int) and work regardless of whether the machine is a two's complement machine or not.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

跨年 2024-09-07 12:25:46

对于 24 位字符串:

当您解析十六进制字符串时,标准 strtol 函数会将其读取为 0 -> 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;
}

For a 24-bit string:

When you parse the hex string, the standard strtol function will read it as an unsigned value in the range 0 -> 2^24 - 1.

The range 0 -> 2^23 - 1 is correct, but the range 2^23 -> 2^24 - 1 needs to be mapped to -2^23 -> -1 which is a simple subtraction which can be performed as follows.

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

To convert a 32-bit string using the same technique you have to use an intermediate type that can represent a full 32-bit unsigned integer in a signed type for performing the subtraction. A long long int is guaranteed to be 64-bits so you can use this.

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;
}
等待我真够勒 2024-09-07 12:25:46

我们有一个 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;
}

We have a SIGN_EXTEND macro, that looks like:

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

It relies on the >> operator 1-filling the input when the sign bit is set. Use it like:

SIGN_EXTEND(0x89abcd, 23, int32_t);

For your problem, you could use:

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;
}
送君千里 2024-09-07 12:25:46

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

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

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

This comparison is wrong: if (toupper (string[0]) == 'F')

You'll need to sign-extend for any value with the MSB set, so something like:

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

徒留西风 2024-09-07 12:25:46

有没有理由不能将 strtol 与基数 16 一起使用?

Is there a reason why you cannot use strtol with radix 16?

GRAY°灰色天空 2024-09-07 12:25:46
  if (toupper (string[0]) == 'F')
  {
     return (result | 0xFF000000);
  }

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

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

这总是会产生积极的结果

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

this will produce number with correct sign.

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

this will always produce positive result

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文