Как получить фактический адрес указателя в C? - PullRequest
3 голосов
/ 28 апреля 2010

ФОН:
Я пишу одноуровневый кеш-симулятор на C для домашнего задания, и мне дали код, с которого я должен работать. В наших обсуждениях кеша нам говорили, что маленький кеш может хранить большие адреса, разбивая большой адрес на позицию в кеше и идентифицируя тег. То есть, если у вас был кэш с 8 слотами, но вы хотели сохранить что-то с адресом больше 8, вы берете 3 (потому что 2 ^ 3 = 8) крайних правых бита и помещаете данные в это положение; так что если бы у вас был адрес 22, например, двоичный 10110, вы бы взяли эти 3 крайних правых бита 110, которые являются десятичными 5, и поместили их в слот 5 кэша. Вы также должны хранить в этой позиции тег, который является оставшимися битами 10.

Одна функция, cache_load, принимает один аргумент и целочисленный указатель. Таким образом, мне дают этот int * addr, который является реальным адресом и указывает на какое-то значение. Чтобы сохранить это значение в кеше, мне нужно разделить адрес. Однако компилятору не нравится, когда я пытаюсь работать с указателем напрямую. Так, например, я пытаюсь получить позицию, выполнив:
npos=addr%num_slots

Компилятор злится и выдает мне ошибки. Я попытался привести к int, но это фактически дало мне значение, на которое указывает указатель, а не сам числовой адрес. Любая помощь приветствуется, спасибо!

[править]

int load(int * addr) { 
  int value = (use_memory ? (*addr) : 0);
  intptr_t taddr=(intptr_t) addr;
  int npos=taddr % blocks;
  int ntag=taddr / blocks;
  printf("addr is %p, taddr is %p, npos is %d and ntag is %d\n",addr,taddr,npos,ntag);

Когда передается адрес, его фактический адрес равен 58, и он указывает на значение 88. Вывод, который я получаю из этого printf:

адрес равен 58, taddr - 58, npos - 0 и ntag - 11

Таким образом, кажется, что taddr получает 58 (при печати с% p, по-прежнему показывает 88 при печати с% d), но npos и ntag отображаются как 0 и 11 (как будто математические операции выполняются с 88) вместо 2 и 7, как я хотел бы.

Код используется так:

void load_words (int n, int words[]) {
  int i;
  for (i=0; i<n; i++) {
    load( (int *) (words[i] * 4));
    cache_print();
  }
}

Ответы [ 5 ]

4 голосов
/ 28 апреля 2010

Вы должны использовать что-то вроде

int *pointer;
intptr_t address=(intptr_t) pointer;

и это в основном просто исправление на посту Эндрю

Таким образом, ваша функция должна стать

(упс забыл, это была домашняя работа. Я вернусь к этому вопросу через некоторое время. Не могу дать прямой ответ :))

4 голосов
/ 28 апреля 2010

Стандарт C99 говорит, что преобразование из типа указателя в целочисленный тип или наоборот является поведением, определяемым реализацией (6.3.2.3.5 и 6.3.2.3.6), за исключением случаев, когда используется intptr_t или uintptr_t определено в <stdint.h>, однако 7.18.1.4 говорит, что эти два типа не являются обязательными, и реализация не должна предоставлять их.

0 голосов
/ 28 апреля 2010

Одна важная вещь, не упомянутая здесь. Когда вы печатаете указатель со спецификатором% p, вам следует привести аргумент:

printf("addr is %p\n", (void *)addr);

% p ожидает указатель на void, и несоответствие спецификатора / аргумента для printf является неопределенным поведением.

0 голосов
/ 28 апреля 2010

Десятичное число 88 равно 0x58 (гекс 58). Когда вы используете спецификатор% p с printf, шестнадцатеричное представление распечатывается. Таким образом, и addr, и taddr являются десятичными 88, и ваши вычисления верны.

0 голосов
/ 28 апреля 2010
int *pointer;
uint32_t address = (uint32_t) pointer;

За исключением, конечно, у вас нет гарантии, что int * помещается в uint32_t, поэтому вам нужно выбрать правильные типы для вашей платформы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...