我使用的语言是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
stdout中显示的结果是:
8048350 134524916
S 600aa0 1
I 4005b6 5
I 4005bb 5
I 4005c0 5
S 7ff000398,8
显然,结果有一条额外的线路无处可去。有人知道这会怎么样吗? THX!
答案 0 :(得分: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
,然后与数据同步,直到最后一行。格式末尾的换行符(就像格式字符串中的任何其他空格一样)会占用空白区域,这就是为什么尽管前导空白但最后一行仍然有效。
答案 1 :(得分:1)
作为转换规范的指令定义了一组 匹配输入序列,如下面针对每个说明符所述。一个 转换规范按以下步骤执行:
输入空白字符(由isspace函数指定) 被跳过,除非规范包括[,c或n说明符。
除非指定,否则从流中读取输入项 包括一个n说明符。
[...]
第一次调用fscanf时,%c会读取文件中的第一个空格。你的空格字符读取零个或多个空白字符,这次是零。您的%lx无法匹配文件中的S字符,因此fscanf将返回。您不检查结果。您的变量包含它们从早期操作中获得的值。
第二次调用fscanf时,%c会读取文件中的第一个S字符。从那时起,其他一切也都成功了。
在编辑中添加,这是对格式字符串的最简单更改,以解决您的问题:
" %c %lx,%d\n"
开头的空格将读取零空格的零个或多个字符,然后%c将读取文件中的第一个非空白字符。
这是另一种格式字符串,它也可以解决您的问题:
" %c %lx,%d"
原因是如果您连续两次读取并丢弃零个或多个空白字符,结果与仅执行一次相同。
答案 2 :(得分:0)
我认为fsanf将第一个字符[space]读入lsm
然后无法读取address
和objsize
,因为格式转换与该行的其余部分不匹配。
然后它会打印一个空格,然后在address
和objsize
声明时发生
编辑 -
fscanf在每次通话后消耗空白,如果你打电话给ftell,你会看到
printf("%c %lx %d %d\n",lsm,address,objsize,ftell(mem_trace));