【问题标题】:Use scanf to take hex instructions input from the user and save them in char. (C)使用 scanf 从用户那里获取十六进制指令输入并将它们保存在 char 中。 (C)
【发布时间】:2018-08-08 08:34:51
【问题描述】:

所以,我正在构建一个应该修改二进制文件中特定字节数的程序。您首先输入二进制文件,然后输入要替换十六进制指令的偏移量,然后输入字节本身。

示例: 我加载example.exe 我指定偏移量0(文件开头) 我指定十六进制指令:4D FF 33 FD FE 该文件的前 5 条指令应替换为我提供的指令。我使用fwrite 进行修改,使用scanf 获取偏移量和十六进制指令,但是,我找不到将它们实际存储为十六进制的方法。 fwrite 实际上将4D FF 33 FD FE 作为二进制文件中的文本而不是十六进制写入。我假设我首先将它们错误地保存在char 中。我是 C 新手,所以我在网上找到的东西并没有真正帮助。

这是我的代码:

      scanf("%ld",&offset_ed);//get the offset from the user.
      fseek(f, offset_ed, SEEK_SET);
      printf("Specify HEX bytes to be written to the binary:  ");
      scanf("%s\n", &hexes);
      fwrite (hexes , sizeof(char), sizeof(hexes), f);
      fclose (f);

其中 hexes 是一个 char hexes;

【问题讨论】:

  • 使用fgets() 读取用户输入的,然后使用strtol()sscanf( ,"%x %n", ) 解析“十六进制字节”。
  • 您需要使用"wb" 打开文件并小心,您不会神奇地替换字节。可能您必须将文件复制到另一个文件并重命名它。
  • 我知道我需要正确打开文件,但我实际上是在使用 r+,是不是很糟糕?此外,问题在于用户输入没有被视为十六进制而是纯文本。
  • @chux 介意举个小例子吗?我对此很陌生。
  • 您正在阅读带有 %s 的文本。您需要将其转换为二进制。

标签: c hex scanf


【解决方案1】:

您已将十六进制作为字符串,因此您需要将它们中的每一个转换为无符号字符(一个字节),然后才能将它们写入文件。

#include <string.h>
#include <stdio.h>
#define ishexchar(c) (c>='A' && c<='F') || (c>='a' && c<='f')
#define toupper(c) c - 32
#define isupper(c) c>='A' && c<='F'

unsigned char hexconv(const char* str, int size){
    unsigned char ret = 0;
    for(int i=0; i<size; i++){
        if(ishexchar(str[i])){
            char c = (isupper(str[i])) ? str[i] : toupper(str[i]);
            ret = (ret*16) + (c - 'A') + 10;
        }else{
            ret = (ret*16) + (str[i] - '0');
        }
    }
    return ret;
}

int main(){
    printf("%x\n",hexconv("4b", 2));
}

上面的代码可能需要根据您的需要进行一些修改,但它可以编译并且可以工作。

【讨论】:

  • 介意举个例子吗?
  • isupper()toupper() 都是标准 C 库函数。最好在此处使用不同的名称以避免冲突和代码误解。
  • 使用#define ishexchar(c) ((c)&gt;='A' &amp;&amp; (c)&lt;='F') || ((c)&gt;='a' &amp;&amp; (c)&lt;='f') 会更清楚。它适用于 ASCII 甚至 EBCDIC
  • 谢谢。我会解决的。
  • 关于#define toupper(c) c - 32,最好添加()以确保评估-#define toupper(c) ((c) - 32)。当然,与 OP 的代码没有区别,但这是一种很好的做法。
【解决方案2】:

总体思路如下。

不要使用scanf(),使用fgets() 读取用户输入的

省略错误检查(用 // ** 注明)

 char buf[100];   // Use some reasonable upper bound of expected user input.

 puts("prompt for input");
 fgets(buf, sizeof buf, stdin);     // **
 offset_ed = strtol(buf, NULL, 10); // **
 fseek(f, offset_ed, SEEK_SET);     // **

 puts("prompt for input");
 fgets(buf, sizeof buf, stdin);  // **
 size_t byte_count = 0;
 unsigned char hexes[(sizeof buf)/2] = 0;  // place to save the "hex bytes"
 int n = 0;
 unsigned byte; 

现在解析字符串以查找十六进制输入。

 // Use "%n" to save the offset of the scan to later update `p`
 // Robust code would use `strtol()` for its better error handling
 char *p = buf;
 while (sscanf(p, "%x %n", &byte, &n) == 1) {
   if (byte > 0xFF) Handle_OutOfRange();
   hexes[byte_count] = byte;
   p += n;  
 }  

 if (byte_count == 0) Handle_EmptyUserInput();
 if (*p) Handle_ExtraJunkInUserInput();
 fwrite (hexes , byte_count, sizeof hexes[0], f); // **

OP 有scanf("%s\n",..."\n" 是个问题。 scanf() 将阻塞,直到用户在预期输入之后输入一些非空白。避免这种情况。

这个问题可以scanf()处理,但是很丑。实际上,代码需要使用scanf("%*1[^\n]") 等在多个“十六进制”字节之后的某处寻找'\n'scanf() 不是这里实现整体编码目标的最佳工具。 scanf() 很少是棚子里最锋利的工具。

【讨论】:

  • 这给出:错误:数组初始值设定项必须是无符号字符十六进制的初始值设定项列表或字符串文字[(sizeof buf)/2] = 0;和错误:对“while (sscanf(p, "%x %n", &byte, &end) == 1)" 使用未声明的标识符 'end'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多