具有内存映射的 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——一个简单的整数运算——然后转换结果。
我目前正在编写一个基本的操作系统作为一个学习项目。为此,我使用了 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——一个简单的整数运算——然后转换结果。