所以这完全是出于我自己的好奇心,我想通过每个内存地址从0x000000一直到我硬盘的最后一个地址。所以我写了这个C片段:
#include <stdio.h>
int main() {
void* ptr = 0x00000;
int x = 0;
while ( x == 0 ) {
puts("hi");
printf("%p\t%c\n",ptr,*(int*)ptr);
ptr++;
}
}
&#34;喜&#34;我在segfault之前只打印一次。什么存储在0x000000,为什么我无法访问它?
答案 0 :(得分:4)
那里什么都没有。空指针指向任何东西,这就是它崩溃的原因。你在做*NULL
。事实上,在当前使用的几乎任何平台上,NULL
被定义为0
(虽然注意到标准实际上并没有保证这一点,并且可能存在一些不同的平台,它有所不同)。
无论如何你都无法访问随机内存。它指向哪里? 你的地址完全无效,在这种情况下你会得到一个段错误,或者它指向其他程序的内存,你不能访问它,你仍然会遇到段错误。
在现代系统中,你甚至没有直接指向内存。地址是虚拟的。如果地址是您的,并且有意义,操作系统将使用page table将其转换为真实地址。如果地址不是您的,则会出现段错误。
如果你有一个非常古老的系统(想象一个8位微型)或一个简单的微控制器,没有虚拟内存或多任务或类似的东西,那么你实际上可以做到这一点。但在现代系统中,你做不到。
答案 1 :(得分:1)
首先,你不是在看操作系统; 你正在查看自己进程的已分配内存。 用这种方法你能看到的最多 是你的过程的形象 (可能包括您链接到的任何图书馆)。
其次,除非你做的事非常特别, 您正在使用virtual memory,marinus says。 您的进程中的虚拟地址0x001000 可能映射到物理地址0x01234000; 虚拟地址0x002000可能映射到物理地址0x42017000。 某些虚拟地址可能根本无法映射到任何地方 - 考虑一下,在32位机器上,你可以有2个 32 地址。 这是4 GiB - 没有多少计算机甚至拥有那么多的物理内存。 (我们甚至不考虑64位机器!) 即使系统有4 GiB的物理内存, 它不会全部映射到您的虚拟地址空间, 因为它会包含其他进程的内存(是的,内核内存)。
正如marinus所提到的,值为0的指针是空指针。 C Programming Language Specification, 第6.3.2.3节“指针”第3段说,
值为0的整数常量表达式, 或者这样的表达式转换为
void *
类型, 被称为空指针常量。 如果将空指针常量转换为指针类型, 结果指针,称为空指针, 保证比较不等于指向任何对象或函数的指针。
第二句话意味着什么都没有 在空指针地址(0地址), 因为,如果那里有东西, 那么指向该对象的指针将等于空指针。 因此, C运行时环境设置虚拟→物理内存映射 像这样的东西:
(建立在the Wikipedia page中的那个), 其中虚拟地址0始终配置为不映射到任何内容。
C语言并不总是指定此行为。 最近25-30年前, 程序可以访问虚拟内存位置0 - 特别是在16位系统上, 和内存管理架构不够复杂的机器 允许系统使内存页面0无法访问 而不会牺牲大部分虚拟地址空间。