0

我使用的语言是 C 我正在尝试从文件中扫描数据,代码段如下:

char lsm;
long unsigned int address;
int objsize;
while(fscanf(mem_trace,"%c %lx,%d\n",&lsm,&address,&objsize)!=EOF){
    printf("%c %lx %d\n",lsm,address,objsize);
}

我从中读取的文件的第一行如下:

 S 00600aa0,1
I  004005b6,5
I  004005bb,5
I  004005c0,5
 S 7ff000398,8

标准输出中显示的结果是:

  8048350 134524916
S 600aa0 1
I 4005b6 5
I 4005bb 5
I 4005c0 5
S 7ff000398,8

显然,结果有一条额外的线,无处可去。有没有人知道这是怎么发生的?谢谢!

4

3 回答 3

1

这适用于您提供的数据:

#include <stdio.h>

int main(void)
{
    char lsm[2];
    long unsigned int address;
    int objsize;
    while (scanf("%1s %lx,%d\n", lsm, &address, &objsize) == 3)
        printf("%s %9lx %d\n", lsm, address, objsize);
    return 0;
}

有多种变化。最简单和最不重要的是从 更改fscanf()scanf(); 这是为了我的方便。

一个重要的变化是将类型lsm从单个char字符变为两个字符的数组。格式字符串然后使用%1s读取一个字符(加上 NUL '\0')到字符串中,但它也(这是至关重要的)跳过前导空格。

另一个变化是在条件中使用了== 3代替!= EOF。如果出现问题,则scanf()返回成功匹配的数量。假设它读到了一个字母,但后面不是一个十六进制数字;它会返回 1(不是 EOF)。此外,它会在每次迭代中返回 1,直到找到与十六进制数匹配的内容。始终测试您期望的值的数量。

输出格式用%9lx. 我在 64 位系统上进行测试,所以 9 位十六进制转换得很好。一个问题scanf()是,如果您在转换时出现溢出,则行为是未定义的。

输出:

S    600aa0 1
I    4005b6 5
I    4005bb 5
I    4005c0 5
S 7ff000398 8

你为什么得到你得到的结果?

第一次转换将空格读入lsm,但随后未能转换S为十六进制数,因此将其留给下一个循环。因此,您在地址和对象大小列中打印了剩余的垃圾。第二次迭代读取S并与数据同步,直到最后一行。格式末尾的换行符(与格式字符串中的任何其他空格一样)吃掉空格,这就是为什么最后一行尽管有前导空格仍然有效。

于 2012-06-26T04:45:22.133 回答
1

作为转换规范的指令定义了一组匹配的输入序列,如下面的每个说明符所述。转换规范按以下步骤执行:

输入空白字符(由 isspace 函数指定)将被跳过,除非规范包含 [、c 或 n 说明符。

从流中读取输入项,除非规范包含 n 说明符。

[...]

第一次调用 fscanf 时,%c 会读取文件中的第一个空格。您的空白字符读取零个或多个空白字符,这次是零个。您的 %lx 无法匹配文件中的 S 字符,因此 fscanf 返回。你不检查结果。您的变量包含它们从早期操作中获得的值。

第二次调用 fscanf 时,%c 读取文件中的第一个 S 字符。从那时起,其他一切也都成功了。

在编辑中添加,这是对格式字符串的最简单更改以解决您的问题:

" %c %lx,%d\n"

开头的空格将读取零个或多个空白字符,然后 %c 将读取文件中的第一个非空白字符。

这是另一种格式字符串,也可以解决您的问题:

" %c %lx,%d"

原因是如果您连续两次读取并丢弃零个或多个空白字符,结果与只执行一次相同。

于 2012-06-26T04:49:01.943 回答
0

我认为 fsanf 将第一个字符 [空格] 读入lsm然后无法读取addressobjsize因为格式转换与该行的其余部分不匹配。

然后它会打印一个空格,然后打印出任何内容address以及objsize何时声明

编辑 -

fscanf 在每次调用后使用空格,如果你调用 ftell 你会看到

printf("%c %lx %d %d\n",lsm,address,objsize,ftell(mem_trace));
于 2012-06-26T03:47:00.413 回答