【问题标题】:How to cast hex value to WORD, DWORD or QWORD and store the result in a double variable?如何将十六进制值转换为 WORD、DWORD 或 QWORD 并将结果存储在双变量中?
【发布时间】:2016-07-05 06:33:57
【问题描述】:

我正在尝试通过这种方式将带符号的十六进制数转换为 WORD、DWORD 和 QWORD:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

int main(void) {

  printf("WORD=%d\n",  (int16_t) strtol("F123", NULL, 16));
  printf("DWORD=%d\n", (int32_t) strtol("FFFFF123", NULL, 16));
  printf("QWORD=%lld\n", (int64_t) strtol("FFFFFFFFFFFFF123", NULL, 16));

  return 0;
}

但它返回以下内容:

WORD=-3805
DWORD=2147483647
QWORD=2147483647

http://ideone.com/mqjldk

但是为什么 DWORD 和 QWORD 转换也没有返回 -3805?

我的意思是:存储在 DWORD 中的 0xFFFFF123 将包含十进制的 -3805 值,而不是 2147483647

预期输出:

WORD=-3805
DWORD=-3805
QWORD=-3805

您有按位选择吗?

【问题讨论】:

  • 对于 WORD 和 DWORD 大小写,您必须使用 "%d" 而不是 "%ld"
  • 没有按预期工作?预期结果是什么?
  • 我猜整个 printf 为 -3805...
  • 我已经编辑了这个问题。存储在 DWORD 中的 0xFFFFF123 将包含十进制的 -3805 值,而不是 2147483647。

标签: c casting hex dword


【解决方案1】:

如果 long int 有 32 位,0xFFFFF123 超出了 long int 的范围,因此 strtol() 返回 LONG_MAX(在我们的例子中为 0x7FFFFFFF = 2147483647)。

使用 strtoull() 将字符串转换为至少 64 位的无符号整数,并在继续之前始终检查错误。

要打印具有指定位大小的整数,请使用以下内容:

printf("foo=%"PRIu32"\n",(uint32_t) foo);

更好的方法:

#include <stdio.h>
#include <stdlib.h>
#define __STDC_FORMAT_MACROS  //we need that for PRI[u]8/16/32 format strings
#include <inttypes.h>
#include <errno.h>

void error_exit(void)
  {
    perror("ups");
    exit(EXIT_FAILURE);
  }

int main(void) 
  {
    unsigned long long temp;
    errno=0;
    temp = strtoull("FFFFF123", NULL, 16);
    if(errno)
      {
        error_exit();
      }
    printf("DWORD=%"PRId32"\n", (int32_t) temp );
    errno=0;
    temp = strtoull("FFFFFFFFFFFFF123", NULL, 16);
    if(errno)
      {
        error_exit();
      }
    printf("QWORD=%"PRId64"\n", (int64_t) temp );

    return EXIT_SUCCESS;
  }

【讨论】:

  • 这并不能解释为什么第二个例子不是否定的。
  • 0xFFFFF123 是正数,不是负数。
  • 不是 32 位的。
  • 是的,当您转换大于 0x7FFFFFFF 的正数并将其转换为 int32_t 时会发生什么?无论如何,由于许多不同的原因,问题中的所有 3 个示例都是荒谬的。
  • 0xFFFFFFFF 和 -1 在 32 位 int 上具有相同的位表示,但 strtol 不关心位表示,如果可以,十进制数 4294967295 必须读取为 -1 而不会出错。 (在 long 为 32 位长的系统上)
【解决方案2】:

strtol 不假定二进制补码输入。为了让它将某些东西视为负数,您必须使用减号。例如"-F123"。这就是为什么第 2 行和第 3 行没有给出负输出的原因。

在第一行的情况下,您得到预期的输出大多是偶然的。因为在strtol 调用之后,您将十六进制值0xF123 转换为int16_t。它不适合int16_t,因此它会被转换为负值。

一些错误:

  • 如果long 不能保存结果,strtol("FFFFFFFFFFFFF123") 将不起作用。你应该使用strtoll。
  • 要打印 stdint.h 类型,请使用 inttypes.h 中的格式说明符 PRId,例如:printf("WORD=%" PRId16 "\n", my_int16_t);
  • 总的来说,避免有符号数的整数溢出。如果您希望输入适合无符号 32 变量而不是有符号变量,则应使用 strtoul 等函数,然后转换为有符号类型。

【讨论】:

    【解决方案3】:

    这段代码中有一些错误。

    第一行的主要问题是您不能将 long int 转换为 int16_t,因为 int16_t 的大小小于 long int。 此外,您应该使用PRId16 说明符来打印int16_t。

    第二行导致打印LONG_MAX,因为0xFFFFF123 is out of range for a long int。

    第三行与第二行有同样的问题,FFFFFFFFFFFFF123 甚至超出范围,将其转换为 64 位值也无济于事。 此外,您需要使用 %lld 或 PRId64 打印它,正如 Michael 已经说过的那样。

    【讨论】:

      【解决方案4】:

      问题在于strtol 的最大输入为 0x7fffffff(或 LONG_MAX)。如果要转换的数字超出范围,则设置errno,结果为LONG_MAX 或LONG_MIN,详情请参阅strtol documentation。

      插图:

      #include <stdio.h>
      #include <stdlib.h>
      #include <errno.h>
      
      int main() {
      
        int x = strtol("7f000000", NULL, 16);  // in range
        printf ("x = %d, errno = %d\n", errno);
      
        x = strtol("F0000000", NULL, 16);      // out of range
        printf ("x = %d, errno = %d\n", errno);
      
        return 0;
      }
      

      输出:

      x = 2130706432, errno = 0
      x = 2147483647, errno = 34
      

      【讨论】:

        猜你喜欢
        • 2014-11-30
        • 1970-01-01
        • 1970-01-01
        • 2012-11-30
        • 2013-09-19
        • 1970-01-01
        • 2013-09-27
        • 2016-07-05
        • 2011-08-25
        相关资源
        最近更新 更多