这是如何取消引用的?

How is this dereferenced?

我正在学习一个教程,他们想在其中写入特定值 (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吗?

广告。 1:C 允许将整数值转换为指针,反之亦然。您是否将(中间)转换分配给变量的天气无关紧要。代码部分(volatile uint32*)(0x04000000)实际上是将整型字面量0x0400000转换为uint32*类型的指针;请注意 volatile,它会关闭所有编译器优化,并让代码在取消引用时实际访问相应的内存。

广告2:没有指向指针的指针; *((volatile uint32*)(0x04000000)) 只是取消引用指针(已在 (1) 中解释)。

我猜这是关于 GameBoy Advance 开发的。

您可以在不声明任何变量的情况下写入内存地址,指针是一种表示内存地址的值类型,您可以写入和读取它而无需将其存储在任何地方。

它不是指向指针的指针,它是一个硬编码地址,被强制转换为 (volatile uint32*),并且宏在前面添加了 * 运算符只是为了避免您编写它,这只是令人困惑。

我最近在做GBA开发的框架,也许你可以从there中挑选一些资料或代码,不过注意代码是C++14。

只是一个评论。所有这些只能由实现定义,因为语言本身没有寄存器存在于众所周知地址的概念。

标准在 6.3.2.3 指针 §5 中说(强调我的):

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

这意味着这是有效的 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;给指向的变量赋值

因为您想访问物理寄存器,您需要要求编译器立即写入值,而不是将其保存在内部寄存器中,这根据 是允许的,就像 规则。这就是 volatile 限定符的含义。由于它专用于特定的实现,因此它是完全合法的,前提是您可以确定 unsigned int 在该实现中具有 32 位,写成

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

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