【问题标题】:How do I read hex numbers into an unsigned int in C如何将十六进制数字读入 C 中的无符号整数
【发布时间】:2010-11-26 16:09:01
【问题描述】:

我想将文本文件中的十六进制数字读入无符号整数,以便执行机器指令。它只是一个模拟类型的东西,它在文本文件中查看并根据值及其相应的指令输出寄存器中的新值。

例如,说明是:

  • 1RXY -> 保存寄存器 R 的值 内存地址XY
  • 2RXY -> 用值 XY 保存寄存器 R
  • BRXY -> 如果 xy 是,则跳转到寄存器 R 这个那个等等。
  • ARXY -> AND 寄存器 R 的值为 内存地址XY

文本文件在新行中包含类似的内容。 (十六进制)

  • 120F
  • B007
  • 290B

我的问题是将每个单独的指令复制到一个无符号整数中......我该怎么做?

#include <stdio.h>
int main(){
    FILE *f;
    unsigned int num[80];

    f=fopen("values.txt","r");
    if (f==NULL){
        printf("file doesnt exist?!");
    }

    int i=0;
    while (fscanf(f,"%x",num[i]) != EOF){
        fscanf(f,"%x",num[i]);
        i++;
    }
    fclose(f);
    printf("%x",num[0]);
}

【问题讨论】:

  • 那是 CHIP8 吗? (15 个字符)。

标签: c file copying


【解决方案1】:

在这种情况下,当您尝试读取小写十六进制时,您的所有输入都是大写十六进制

要修复它,请将 %x 更改为 %X

【讨论】:

  • 或者您可以使用strtol(),它可以任意控制您想要的基数,并且可能会稍微快一些,因为它不必解析格式字符串。并不是说我天生倾向于回避scanf()printf() 只是因为解析格式字符串或任何东西所需的轻微开销......
  • 克里斯:你说得对,我的错!我忘记了为什么我这么认为……编辑了。
  • 这是错误的 - %x%X 说明符完全相同
【解决方案2】:

您正在将两个数字读入数组的每个元素(因此在覆盖它们时会丢失其中的一半。尝试仅使用

while (i < 80 && fscanf(f,"%x",&num[i]) != EOF)
    i++;

为你的循环

编辑

您还缺少 '&' 来获取数组元素的地址,因此您将随机垃圾指针传递给 scanf 并且可能会崩溃。 -Wall 选项是您的朋友。

【讨论】:

    【解决方案3】:

    您是否希望将每一行(每行 4 个字符长)分隔为 4 个不同的数组元素?如果你这样做,我会试试这个:

    /* read the line */
    /* fgets(buf, ...) */
    
    /* check it's correct, mind the '\n' */
    /* ... strlen ... isxdigit ... */
    
    /* put each separate input digit in a separate array member */
    num[i++] = convert_xdigit_to_int(buf[j++]);
    

    convert_xdigit_to_int() 函数只是将 '0'(字符)转换为 0(int)、'1' 转换为 1、'2' 转换为 2、...'9' 转换为 9、'a' 或'A' 到 10,...

    当然,伪代码是在一个循环中执行的,直到文件用完或数组被填满。也许将 fgets() 作为条件一段时间(...)

    while(/*there is space in the array && */ fgets(...)) {
    }
    

    【讨论】:

      【解决方案4】:

      你在正确的轨道上。这是我看到的问题:

      • 如果fopen() 返回NULL,您需要退出 - 您正在打印错误消息,然后继续。
      • 如果出现i &gt;= 80,您的循环应该终止,因此您读取的整数不会超过您的空间。
      • 您需要将num[i] 的地址而不是值传递给fscanf
      • 您在循环中调用了两次fscanf(),这意味着您丢弃了一半的值而不存储它们。

      以下是修复这些问题后的样子:

      #include <stdio.h>
      
      int main() {
          FILE *f;
          unsigned int num[80];
          int i=0;
          int rv;
          int num_values;
      
          f=fopen("values.txt","r");
          if (f==NULL){
              printf("file doesnt exist?!\n");
              return 1;
          }
      
          while (i < 80) {
              rv = fscanf(f, "%x", &num[i]);
      
              if (rv != 1)
                  break;
      
              i++;
          }
          fclose(f);
          num_values = i;
      
          if (i >= 80)
          {
              printf("Warning: Stopped reading input due to input too long.\n");
          }
          else if (rv != EOF)
          {
              printf("Warning: Stopped reading input due to bad value.\n");
          }
          else
          {
              printf("Reached end of input.\n");
          }
      
          printf("Successfully read %d values:\n", num_values);
          for (i = 0; i < num_values; i++)
          {
              printf("\t%x\n", num[i]);
          }
      
          return 0
      }
      

      【讨论】:

      • +1 我会将rv 声明为您使用它的循环的本地,但这并不是什么大问题。
      • rv 在循环外可用,以便您区分匹配失败和读取失败/EOF。
      【解决方案5】:

      您也可以使用函数 strtol()。如果您使用 16 为基数,它会将您的十六进制字符串值转换为 int/long。

      errno = 0;
      my_int = strtol(my_str, NULL, 16);
      /* check errno */
      

      编辑:另外一点,各种静态分析工具可能会将 atoi() 和 scanf() 之类的东西标记为不安全。 atoi 已过时,因为它不像 strtol() 那样检查错误。另一方面,scanf() 可以进行各种缓冲区溢出,因为它不检查发送到 scanf() 的类型。例如,你可以给一个指向 scanf 的 short 的指针,其中读取的值实际上是 long ......并且繁荣。

      【讨论】:

      • 这是因为如果strtol成功,它不会改变errno,您需要检查这种情况,以区分ERANGE错误和导致LONG_MAX的成功转换或LONG_MIN.
      • 如果您打算在调用后立即检查,最好在函数调用之前将 errno 设置为零。在该调用之前,errno 的值可能已通过其他方式更改。
      • 来自 strtol 手册页:errno = 0; /* 在调用之后区分成功/失败/ val = strtol(str, &endptr, base); / 检查各种可能的错误 */
      • sscanf 和好友的代价是残酷的。在 callgrind 调查下,它给了我们大约 81.44 的成本,而使用 strtol 时,它是 0.12。所以我们按照@KFro 的建议从 scanf 转移到 strol...
      猜你喜欢
      • 2015-12-02
      • 2011-06-15
      • 2017-04-19
      • 2011-08-21
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 2021-11-05
      相关资源
      最近更新 更多