我正在用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行为的文档。
答案 0 :(得分:1)
address
变量的类型为long
,只能存储4个字节,而0x7ff000398
是8个字节。因此它仅存储最后4个有效字节,而忽略最高有效字节。
这就是第1行和第2行按预期运行但第3行不按预期运行的原因。
要解决此问题,您可以将地址类型更改为long long
答案 1 :(得分:0)
您将需要64位整数来存储结果。
在32位系统上,long
类型可能只有32位长。
可以肯定的是,您可以对long long
使用address
类型。
更好的做法是使用uint64_t
类型(在c99的stdint.h
中定义)
address
的类型更改为long long
(如果需要)%x
更改为%lx
(对于long
)或%llx
(对于long long
)(两个地方)在打开警告的情况下,您应该得到以下消息:
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;
}