3

我正在尝试通过这种方式将带符号的十六进制数转换为 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呢?

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

预期输出:

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

你有按位选择吗?

4

4 回答 4

5

如果 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;
  }
于 2016-03-18T13:46:52.467 回答
4

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

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

一些错误:

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

这段代码中有一些错误。

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

第二行导致打印超出 long intLONG_MAX0xFFFFF123范围。

第三行与第二行具有相同的问题,FFFFFFFFFFFFF123甚至超出范围并将其转换为 64 位值无济于事。此外,您需要使用%lldPRId64按照迈克尔已经说明的方式打印它。

于 2016-03-18T13:49:42.777 回答
0

问题是最大输入为strtol0x7fffffff(或 LONG_MAX)。如果要转换的数字超出范围,errno设置并且结果为LONG_MAXor LONG_MIN,请参阅strtol 文档了解更多详细信息。

插图:

#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
于 2016-03-18T13:57:31.600 回答