有什么内存地址空间?

使用了什么forms的内存地址空间?

今天,大型扁平虚拟地址空间很常见。 从历史上看,已经使用了更复杂的地址空间,例如一对基地址和偏移量,一对段号和一个偏移量,一个字地址加上一个字节或其他子对象的索引,依此类推。

有时,各种答案和评论断言C / C ++指针本质上是整数。 这是一个不正确的C / C ++模型,因为各种地址空间无疑是一些关于指针操作的C规则的原因。 例如,不在数组之外定义指针算法简化了对基本和偏移模型中指针的支持。 指针转换的限制简化了对地址加额外数据模型的支持。

这种反复出现的断言激发了这个问题。 我正在寻找有关各种地址空间的信息,以说明C / C ++指针不一定是一个简单的整数,并且考虑到要支持的各种机器,C / C ++对指针操作的限制是明智的。

有用的信息可能包括:

  • 具有各种地址空间和这些空间的描述的计算机体系结构的示例。
  • 在当前正在制造的机器中仍在使用的各种地址空间的示例。
  • 引用文档或解释,尤其是URL。
  • 详细说明地址空间如何激发C / C ++指针规则。

这是一个广泛的问题,所以我愿意接受有关管理它的建议。 我很乐意看到一个通用包容性答案的协作编辑。 然而,这可能无法授予应得的声誉。 我建议投票多个有用的贡献。

你可以想象的任何东西都可能被使用过。 第一个主要部门是字节寻址(所有现代架构)和字寻址(IBM 360 / PDP-11之前,但我认为现代Unisys大型机仍然是字处理的)。 在字寻址中, char*void*通常大于int* ; 即使它们不是更大,“字节选择器”也将是高位,它们必须是0,否则将被忽略除字节以外的任何东西。 (例如,在PDP-10上,如果pchar*(int)p < (int)(p+1)通常是false,即使intchar*具有相同的大小。)

在字节寻址机器中,主要变体是分段和非分段架构。 今天两者仍然广泛传播,尽管在英特尔32位(具有48位地址的分段架构)的情况下,一些更广泛使用的操作系统(Windows和Linux)人为地将用户进程限制为单个段,模拟平面寻址。

虽然我没有最近的经验,但我希望嵌入式处理器的种类更多。 特别是,在过去,嵌入式处理器经常使用哈佛架构,其中代码和数据位于独立的地址空间中(因此,函数指针和数据指针,转换为足够大的整数类型,可以比较相等) )。

我会说你问的是错误的问题,除了历史的好奇心。

即使你的系统碰巧使用了一个扁平的地址空间 – 事实上,即使从现在到结束的每个系统都使用一个扁平的地址空间 – 你仍然不能将指针视为整数。

C和C ++标准使各种指针算术“未定义”。 在任何系统上,这都会对您产生影响,因为编译器会假设您避免未定义的行为并相应地进行优化。

举个具体的例子,三个月前Valgrind出现了一个非常有趣的错误:

http://comments.gmane.org/gmane.comp.debugging.valgrind.devel/19698

(搜索“未定义的行为”。)

基本上,Valgrind使用小于和大于指针来尝试确定自动变量是否在一定范围内。 因为不同聚合中的指针之间的比较是“未定义的”,所以Clang简单地优化了所有比较以返回常量true(或假;我忘了)。

这个bug本身产生了一个有趣的StackOverflow问题 。

因此,虽然原始指针算术定义可能适用于真实机器,并且这可能是有趣的,但它实际上与今天的编程无关。 今天相关的是你不能假设指针的行为像整数,句点,无论你碰巧使用什么系统。 “未定义的行为”并不意味着“有趣的事情发生”; 这意味着编译器可以假设您不参与其中。 当你这样做时,你会在编译器的推理中引入矛盾; 从矛盾来看,任何事情都遵循……它只取决于你的编译器有多聪明。

而且他们总是变得更聪明。