具有内存映射的 C 指针的奇怪行为 I/O

Strange behaviour of C pointers with memory mapped I/O

我目前正在编写一个基本的操作系统作为一个学习项目。为此,我使用了 gcc 4.9.2 交叉编译器。 在尝试使用内存映射 I/O 时,我偶然发现了我无法理解的 C 指针(或可能是内存映射 I/O)的行为。 通过以下代码直接访问I/O内存时,我得到了预期的结果,即黑底浅灰色字体左上角的"AB"。

*((uint16_t *)0xB8000) = 0x0741;
*((uint16_t *)0xB8002) = 0x0742;

然而,当尝试通过使用向基地址加 2 的偏移量来操作内存时,结果并不像预期的那样 "A" 在第二个位置,而是在第三个位置。

*((uint16_t *)0xB8000 + 2) = 0x0741;

添加 1 而不是 2 打印出第二个位置的字母,但我不明白为什么。由于每个字母(在 MMIO 中)都由 2 个字节的数据组成,因此我假设我需要为下一个字符将写入的内存地址增加 2。 (正如我最初直接写入 0xB8002 所做的那样) 为了尝试理解这种行为,我在一个单独的 C 程序中做了一些测试,但无法复制这种行为: (注意:这段代码是使用普通的gcc 4.8.2编译的)

#include <stdint.h>
#include <stdio.h>

void main(void) {
        printf("0xB8000 + 1 = %x\n", 0xB8000 + 1);
        printf("&(*(uint16_t *)(0xB8000 + 1)) = %x\n", (uint32_t)&(*(uint16_t *)(0xB8000 + 1)));
}

该程序产生了以下输出:

0xB8000 + 1 = b8001
&(*(uint16_t *)(0xB8000 + 1)) = b8001

我假设我遗漏了 C 指针的某种行为,这种行为会导致对语句写入的数据大小进行分解。是这种情况还是我忽略了其他原因?

此致,Kenshooak

如果将整数 n 添加到 <type> 指针,地址将增加 sizeof( <type> ) * n 字节。 所以在你的第一个例子中,你有

*((uint16_t *)0xB8000 + 2) = 0x0741;

所以这里发生的是:0xB8000 被转换为 unit16_t *,然后该指针递增 2,这意味着 2 * sizeof( uint16_t ) = 4 字节

在你的第二个例子中你有

 *(uint16_t *)(0xB8000 + 1)

注意不同的括号:在这里您首先将 1 加到 0xB8000——一个简单的整数运算——然后转换结果。