Направление указателя, когда указатель и ширина данных различаются - PullRequest
3 голосов
/ 09 декабря 2010

Я хочу получить доступ к 32-битным данным, на которые указывает адрес в аппаратном регистре (который является 64-битным, с набором только 40 LSb).Поэтому я делаю:

paddr_t address = read_hw(); // paddr_t is unsigned long long
unsigned int value  = *(unsigned int*) address; // error: cast to pointer from integer of different size
unsigned int value2 = (unsigned int) *((paddr_t*) address); // error: cast to pointer from integer of different size

Каким будет правильный способ сделать это без ошибки компилятора (я использую -Werror)?

Ответы [ 4 ]

1 голос
/ 09 декабря 2010

Номинально с C99 первый вариант наиболее близок к правильному,

uint32_t value = *(uint32_t*)address;

Однако вы также можете использовать другие указатели / целочисленные помощники,

uintptr_t address = read_hw();
uint32_t value = *(uint32_t*)address;
0 голосов
/ 09 декабря 2010

Из того, что вы написали, у вас есть указатель 64, из которых только 40 битов являются указателями, и этот указатель указывает на некоторые данные размером 32 бита.

Ваш код, похоже, пытается исказить40-битный указатель в 32-битный указатель.

Что вы должны сделать, это добавить соответствующие 40 битов в 64-битный указатель, чтобы он оставался 64-битным указателем, а затем использовать его для доступа кданные, которые вы можете затем аналогичным образом и получить данные.В противном случае вы (как показывают ошибки) усекаете указатель.

Что-то вроде (у меня нет 64-битной версии, поэтому я не могу проверить это, но вы поняли):

address = address & 0x????????????????; // use the ?s to mask off the bits you
                                        // want to ignore
value64 = *address; // value64 is 64 bits

value32 = (int)(value64 & 0x00000000ffffffff); // if the data is in the lower
                                               // half of value64
or
value32 = (int)((value64 & 0xffffffff00000000) > 32); // if the data is in the
                                                      // higher half of value64

, где? Маскируют биты по мере необходимости (в зависимости от конечности, с которой вы работаете).

Возможно, вам также придется изменить (int) приведение типов в соответствии (вы хотитевместо этого приведите его к какому-либо 32-битному типу данных, который представляют данные, т.е. к типу значения 32).

0 голосов
/ 09 декабря 2010

Я не уверен, что понимаю вопрос.

"Я хочу получить доступ к 32-битным данным, на которые указывает адрес в аппаратном регистре (который является 64-битным с набором только 40 LSb)."

Итак, у вас есть аппаратный регистр шириной 64 бита, из которых наименее значимые 40 должны интерпретироваться как адрес в памяти, который содержит 32 бита данных?

Можете ли вы попробовать

uint32_t* pointer = (*(uint64_t *) register_address) & (~0 >> 24)
uint32_t value = *pointer

Хотя это может усложниться в зависимости от порядка байтов и от того, интерпретирует ли компилятор >> как логическое или арифметическое смещение вправо.

Хотя, действительно, я хочу спросить,

  1. Означает ли "Я использую кросс-компилятор, у меня нет роскоши printf" означает, что вы на самом деле не можете запустить свой код, или просто вам нужно сделать это на каком-то оборудовании, в котором отсутствует удобный выходной канал
  2. Какова ваша целевая архитектура, что ваши указатели имеют длину 40 бит?!
0 голосов
/ 09 декабря 2010

проверьте реальные размеры ваших указателей и тип paddr_t:

printf("paddr_t size: %d, pointer size: %d\n",
       sizeof(paddr_t), sizeof(unsigned int *));

что вы получаете?

обновление:

ARM is32-битная архитектура, поэтому вы пытаетесь преобразовать 64-битное целое в 32-битный указатель, а вашему компилятору это не понравится!

Если вы уверены, что значение в paddr_t соответствует 32-битному указателю, вы можетепросто приведите его сначала к int:

unsigned int *p = (unsigned int *)(int)addrs;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...