fscanf получает только первые 4 байта шестнадцатеричного числа - PullRequest
0 голосов
/ 16 мая 2019

Я пишу кеш-симулятор на 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..........................

Оператор отладки выводит неверный адрес для строк 3. Вместо «address: 7ff000398» он пишет «address: ff000398». Это правильно для строки 1. Почему он читает только в первых 4 байтах? 'address' уже длинный, и я не могу найти никакой документации о том, как% x ведет себя так.

Ответы [ 3 ]

1 голос
/ 16 мая 2019

Тип address vairable - long, который может хранить только 4 байта, а 0x7ff000398 - 8 байтов. поэтому в нем хранятся только 4 последних значащих байта и игнорируются наиболее значимые. По этой причине строки 1 и 2 работают как положено, а строка 3 - нет.

чтобы исправить это, вы можете изменить тип адреса на long long

0 голосов
/ 16 мая 2019

Начиная с 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;
}
0 голосов
/ 16 мая 2019

Для хранения результата вам потребуется 64-битное целое число.

32-битные системы

В 32-битной системе тип long может иметь длину только 32 бита.

Конечно, вы можете использовать long long тип для address.

Лучше, будет использовать uint64_t тип (определенный в stdint.h на c99)

Изменения

  1. Измените address тип на long long (при необходимости)
  2. Измените %x на %lx (для long) или %llx (для * 1027)*) (два места)
  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
...