Как это разыменовывается? - PullRequest
       25

Как это разыменовывается?

0 голосов
/ 31 декабря 2018

Я следую учебному пособию, в котором они хотят записать определенное значение (0x0403) для регистрации (по адресу 0x04000000)

Насколько мне известно, это можно сделать так,

unsigned int 32 *ptr;
ptr = 0x04000000
*ptr = 0x403

Однако они делают следующее:

#define REG_DISP      *((volatile uint32*)(0x04000000))
#define VIDEOMODE_3                            0x0003
#define BGMODE_2                               0x0400

int main()
{
    REG_DISP = VIDEOMODE_3 | BGMODE_2;
    while(1){}
}

Теперь у меня есть следующие вопросы:

  1. Можем ли мы использовать указатели без объявления каких-либо переменных?

  2. Почему используется указатель на указатель?Это потому, что мы не можем сделать ptr = 0x04000000?

Ответы [ 3 ]

0 голосов
/ 31 декабря 2018

Полагаю, речь идет о разработке GameBoy Advance.

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

Это не указатель на указатель, это жестко закодированный адрес, который приведен к (volatile uint32*), и макрос добавляет оператор * впереди, просто чтобы спасти васот написания этого, что просто сбивает с толку.

Я работаю над каркасом для разработки GBA прямо сейчас, может быть, вы можете выбрать некоторую информацию или код из там , не забывайте, что кодхотя C ++ 14.

0 голосов
/ 31 декабря 2018

Просто замечание.Все это может быть только определено реализацией, потому что сам язык не имеет понятия регистров, живущих по хорошо известным адресам.

Стандарт только что говорит в 6.3.2.3 Указатели § 5 (подчеркните мой):

Целое число может быть преобразовано в любой тип указателя .За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть представлением прерывания.

Это означает, что этодопустимый C, при условии, что реализация позволяет ему иметь смысл:

unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;

Он просто использует именованный указатель для доступа к конкретному адресу.Это можно сделать, не называя указатель таким образом:

* ((unsigned int *) 0x04000000) = 0x403;

Давайте посмотрим, как он работает:

  • (unsigned int *) 0x04000000 преобразует беззнаковое целое в указатель на беззнаковое целое
  • * ((unsigned int *) 0x04000000) разыменовывает, что указатель
  • * ((unsigned int *) 0x04000000) = 0x403; присваивает значение указанной переменной

Когда вы хотите получить доступ к физическому регистру, вам нужно задатькомпилятор немедленно записывает значение, а не хранит его во внутреннем регистре, который может быть разрешен согласно правилу , как если бы .В этом смысл квалификатора volatile.Поскольку оно предназначено для конкретной реализации, оно совершенно законно, при условии, что вы можете быть уверены, что unsigned int имеет 32 бита в этой реализации для записи

volatile unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;

или

* ((volatile unsigned int *) 0x04000000) = 0x403;
0 голосов
/ 31 декабря 2018

Ad.1: C позволяет преобразовать целое значение в указатель и наоборот.Погода вы назначаете (промежуточное) преобразование в переменную или нет, не имеет значения.Часть кода (volatile uint32*)(0x04000000) фактически преобразует целочисленный литерал 0x0400000 в указатель типа uint32*;Обратите внимание на volatile, которое отключает любые оптимизации компилятора и позволяет коду фактически получать доступ к соответствующей памяти при разыменовании.

Объявление 2: указатель на указатель отсутствует;*((volatile uint32*)(0x04000000)) просто разыменовывает указатель (что было объяснено в (1).

...