【问题标题】:How is this dereferenced?这是如何取消引用的?
【发布时间】:2018-12-30 22:00:49
【问题描述】:
我正在关注一个教程,他们希望将特定值 (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){}
}
现在,我有以下问题:
我们可以在不声明任何变量的情况下使用指针吗?
为什么使用指向指针的指针?是不是因为,我们不能做 ptr = 0x04000000?
【问题讨论】:
标签:
c
pointers
dereference
【解决方案1】:
只是一个评论。所有这些都只能由实现定义,因为语言本身没有位于众所周知地址的寄存器的概念。
标准只是在 6.3.2.3 Pointers §5 中说(强调我的):
整数可以转换为任何指针类型。除先前规定外,
结果是实现定义的,可能没有正确对齐,可能不指向
引用类型的实体,可能是陷阱表示。
这意味着这是有效的 C,只要实现允许它有意义:
unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
它只是使用命名指针来访问特定地址。不用这样命名指针也可以做到:
* ((unsigned int *) 0x04000000) = 0x403;
让我们看看它是如何工作的:
-
(unsigned int *) 0x04000000 将 unsigned int 转换为指向 unsigned int 的指针
-
* ((unsigned int *) 0x04000000) 取消引用该指针
-
* ((unsigned int *) 0x04000000) = 0x403; 为指向的变量赋值
当你想访问一个物理寄存器时,你需要让编译器立即写入值,而不是把它保存在一个内部寄存器中,这可能是 as if 规则所允许的。这就是volatile 限定符的含义。因为它专门用于特定的实现,所以它是完全合法的,前提是您可以确定unsigned int 在该实现中具有 32 位,以编写
volatile unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
或
* ((volatile unsigned int *) 0x04000000) = 0x403;
【解决方案2】:
广告。 1:C 允许将整数值转换为指针,反之亦然。是否将(中间)转换分配给变量的天气并不重要。代码部分(volatile uint32*)(0x04000000) 实际上将整型文字0x0400000 转换为uint32* 类型的指针;请注意 volatile,它会关闭任何编译器优化,并让代码在取消引用时实际访问相应的内存。
广告2:没有指向指针的指针; *((volatile uint32*)(0x04000000)) 只是取消引用指针(已在(1)中解释。
【解决方案3】:
我猜这是关于 GameBoy Advance 开发的。
您可以在不声明任何变量的情况下写入内存地址,指针是一种表示内存地址的值,您可以对其进行写入和读取,而无需将其存储在任何地方。
它不是指向指针的指针,它是一个硬编码的地址,它被强制转换为(volatile uint32*),并且宏在前面添加了* 运算符,只是为了避免你编写它,这只是令人困惑。
我最近正在为 GBA 开发框架工作,也许你可以从 there 中挑选一些信息或代码,但请注意代码是 C++14。