我目前正致力于将基本操作系统编写为学习项目。为此,我使用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
答案 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 - 一个简单的整数运算 - 然后转换结果。