fscanf仅获取十六进制数字的前4个字节

时间:2019-05-16 08:32:49

标签: c scanf

我正在用C语言编写一个缓存模拟器,并且几乎完成了所有工作……除非我尝试扫描地址,fscanf跳过了十六进制数字中的一些数字:它只会得到4个字节!如果我无法获得正确的地址,则标记位不正确,并且模拟将始终无法进行。任务似乎很简单,但是我一定错过了一些东西。也许与fscanf格式的字符串特质有关?

源文件如下:

 S 00600aa0,1
I  004005b6,5
 S 7ff000398,8
 M 7ff000390,8
// and so on ...

我尝试改用fgets和sscanf,但得到的结果相同。

char buffer[200];
char *pattern = " %c %x,%s\n";
int status; long address; char op; 
while ((status = fscanf(source, pattern, &op, &address, buffer)) != EOF) { 
    if (op != 'I')  { 
        fprintf(stderr,"address: %x\n",address); // DEBUG stmnt 
        simulate the cache..........................

debug语句为第3行打印出错误的地址,而不是“ address:7ff000398”,而是写入“ address:ff000398”。它正确地适合第1行。为什么只读取前4个字节? “地址”已经很长了,我找不到任何有关%x行为的文档。

3 个答案:

答案 0 :(得分:1)

address变量的类型为long,只能存储4个字节,而0x7ff000398是8个字节。因此它仅存储最后4个有效字节,而忽略最高有效字节。 这就是第1行和第2行按预期运行但第3行不按预期运行的原因。

要解决此问题,您可以将地址类型更改为long long

答案 1 :(得分:0)

您将需要64位整数来存储结果。

32位系统

在32位系统上,long类型可能只有32位长。

可以肯定的是,您可以对long long使用address类型。

更好的做法是使用uint64_t类型(在c99的stdint.h中定义)

更改

  1. address的类型更改为long long(如果需要)
  2. %x更改为%lx(对于long)或%llx(对于long long)(两个地方)
  3. 在打开警告的情况下进行编译。

警告

在打开警告的情况下,您应该得到以下消息:

warning: format ‘%x’ expects argument of type ‘unsigned int’, 
but argument 3 has type ‘long int’ [-Wformat=]
fprintf(stderr,"address: %x\n",address); // DEBUG stmnt
                         ~^    ~~~~~~~
                         %lx

这为您解决问题提供了很好的线索。

因此,您的代码应如下所示:

#include <stdio.h>
int main(void)
{
    char buffer[10];
    char *pattern = " %c %lx,%s\n";
    int status; 
    unsigned long address; char op; 
    while ((status = scanf(pattern, &op, &address, buffer)) != EOF) { 
        fprintf(stderr,"address: %lx\n",address); 
    }
    return 0;
}

通过您的输入,我得到了结果:

address: 600aa0
address: 4005b6
address: 7ff000398
address: 7ff000390

答案 2 :(得分:0)

从C99开始,您可以使用uintptr_t,这是一种无符号整数类型,能够存储指针(如果这些地址是同一目标计算机上的指针)。

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

int main(void)
{
    char *str = "7ff000398";
    uintptr_t address;

    sscanf(str, "%" SCNxPTR, &address); // x for base 16
    printf("%" PRIxPTR "\n", address); // x for base 16
    return 0;
}