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

时间:2015-02-11 18:15:58

标签: c pointers kernel osdev

我目前正致力于将基本操作系统编写为学习项目。为此,我使用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

1 个答案:

答案 0 :(得分:4)

如果向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 - 一个简单的整数运算 - 然后转换结果。