Просто замечание.Все это может быть только определено реализацией, потому что сам язык не имеет понятия регистров, живущих по хорошо известным адресам.
Стандарт только что говорит в 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;