【问题标题】:Read an hexadecimal number and validate its number of digits in C读取一个十六进制数并验证其在 C 中的位数
【发布时间】:2016-11-19 21:06:48
【问题描述】:

我需要在 C 中读取一个带有八位数字的十六进制数字,并且我需要对其进行验证。如果少于八位,则填写“0”。如果超过八位,则打印“请输入有效数字”之类的消息。

我正在做这样的事情:

unsigned int number;

printf("\nIntroduzca un número: ");
scanf("%08x", &number);

但使用“%08x”我可以填写“0”,但我不知道插入的数字是否超过八位并打印错误消息。

我想把它读成一个字符串,但后来我需要对它做位操作,并以十六进制和二进制打印结果,所以我不知道把数字读成字符串是否是个好主意。

我该如何解决这个问题?

【问题讨论】:

  • 我会改为读取一个字符串,检查它的长度,然后使用strtol 和基数 16 将其转换为十六进制。注意:strtol 允许前面有一个可选的 0x,因此您可能需要确保字符串不以此开头。您还可以检查该数字是否不大于ffffffff
  • 使用 sprintf 将数字(返回)转换为字符串,必要时用 0 填充。
  • *printf 使用 %0nx 其中 n 是(非零)宽度,表示用零而不是空格填充,但 *scanf%0nx 没有这种特殊含义; %08x 表示将最多 8 个十六进制字符解析为unsigned int,与%8x 相同。 (另请注意,在某些系统上unsigned int 不是 32 位,但您不太可能遇到它们。)

标签: c hex printf scanf


【解决方案1】:

scanf() 很少是用户输入的最佳选择。最好使用fgets() 读取一行,然后使用附加代码来解析字符串。

char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
  // code read the text input into a string, now do something with it.

代码正在寻找八个十六进制数字,而 OP 正处于正确的轨道上,scanf("%08x"...0 在这里不需要,只需 8 将输入限制为 8 位。使用" " 跳过任何可选的空白。使用"%n"记录解析的字符数。

  unsigned number = 0;
  int n = 0;
  // If any length (up to 8) hex text was found ...
  // ... and test if `buf[n]` is the end of the string or maybe that 9 digit?
  if (sscanf(buf, "%8x %n", &number, &n) == 1) && buf[n] == '\0') {
    printf("Success :%08x\n", number);
  } else {
    fprintf(stderr, "please insert a valid number\n");
  }
}

如果代码需要确保文本不包含 "0x123" 这样的前导,则需要做更多工作。各种方法。

坚持使用*scanf() 说明符,使用"%*[0123456789abcdefABCDEF]" 扫描字符串以查找十六进制数字。 * 表示不保存,只扫描。

  int n = 0;
  // If any length (up to 8) hex text was found ...
  // ... and test if `buf[n]` is the end of the string or maybe that 9 digit?
  sscanf(buf, "%*8[0123456789abcdefABCDEF] %n", &n);
  if (n > 0 && buf[n] == '\0') {
    unsigned long number = strtoul(buf, NULL, 16);
    printf("Success :%08lx\n", number);
  } else {
    fprintf(stderr, "please insert a valid number\n");
  }
}

一个聪明的方法是避免*scanf()一起使用,在要解析的字符串前面加上"0x",只使用strtol()进行解析。

char buf[100];
while (fgets(&buf[2], sizeof buf - 2, stdin)) {
  char *endptr;
  buf[0] = '0';
  buf[1] = 'x';
  unsigned long number = strtoul(buf, &endptr, 16);
  int length = (int) (endptr - buf);
  if (length < 3 || length > (2 + 8) || *endptr != '\n') {
    fprintf(stderr, "please insert a valid number\n");
  } else {
    printf("Success :%08lx\n", number);
  }
}

【讨论】:

  • 最后一部分的聪明技巧利用strtoul(...,...,16)sscanf(..., "%x",...)允许可选的前导"0x"。通过在字符串前面加上"0x",然后解析该字符串,像"0x123" 这样的用户输入将被解析为"0x0x123"。那么停止解析位置不会是字符串的结尾。
  • 你说得对,我决定使用 fgets() 读取该行并对其进行验证,并使用 strtol() 对其进行解析。
【解决方案2】:

将其作为字符串读取。检查前 2 个字节以确保它们没有在开头添加 0x。使用strlen 验证长度。

然后正如@Evert 所说,使用strtol 将其转换为十六进制值,使用基数16。检查strtol 的返回值以验证成功或失败 - 输入的十六进制数是否有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 2015-07-30
    • 2015-03-30
    • 2018-07-05
    • 1970-01-01
    • 2012-04-04
    相关资源
    最近更新 更多