远指针和近指针有什么区别?

有人可以告诉我far指针和C指针之间的区别吗?

在16位x86分段存储器架构上,有四个寄存器用于指代各个段:

  • DS→数据段
  • CS→代码段
  • SS→堆栈段
  • ES→额外段

该体系结构上的逻辑地址是写入segment:offset 。 现在回答这个问题:

  • 近指针指向(作为偏移量)当前段。

  • 远指针使用段信息和偏移来指向段。 因此,要使用它们,DS或CS必须更改为指定的值,内存将被解除引用,然后恢复DS / CS的原始值。 请注意,它们的指针算术不会修改指针的段部分,所以溢出的偏移量就会包裹它。

  • 然后是巨大的指针,这些指针被标准化为具有给定地址的最高可能段(与远指针相反)。

在32位和64位体系结构中,内存模型使用不同的分段,或根本不使用分段。

在DOS等旧平台上使用了远近的指针。

我不认为他们在现代平台上是相关的。 但你可以在这里和这里了解他们(正如其他答案所指出的)。 基本上, 指针是一种在计算机中扩展可寻址内存的方法。 IE,在16位平台上处理超过64k的内存。

由于没有人提到DOS,所以让我们忘掉旧的DOS PC电脑,并从一个通用的angular度来看待这个问题。 那么,非常简单,它是这样的:


任何CPU都有一个数据总线,这是CPU可以在一条指令中处理的最大数据量,即等于其寄存器的大小。 数据总线宽度用位表示:8位,或者16位,或者64位等。这就是“64位CPU”的意思,它是指数据总线。

任何CPU都有一个地址总线,也有一定的总线宽度,以位表示。 CPU可以直接访问的任何存储单元都有唯一的地址。 地址总线足够大,可以覆盖所有可寻址的内存。

例如,如果一台计算机有65536个字节的可寻址内存,则可以用一个16位地址总线来覆盖这些总线,2 ^ 16 = 65536。

数据总线宽度通常(但并非总是)与地址总线宽度一样宽。 如果它们具有相同的大小,它会很好,因为它可以使CPU指令集和为其编写的程序更清晰。 如果CPU需要计算一个地址,那么如果该地址足够小以便能够装入CPU寄存器(通常称为索引寄存器,当涉及到地址)时,则很方便。

far的非标准关键字用于描述系统中需要寻址超出正常CPU地址总线宽度的内存的指针。

例如,对于具有16位数据总线的CPU也可以有一个16位地址总线。 但同一台计算机也可能需要超过2 ^ 16 = 65536字节= 64kb的可寻址内存。

然后CPU通常会有特殊的指令(稍微慢一些),这使得它可以在64kb以外的地址寻址内存。 例如,CPU可以将其大内存分成n 页面 (有时也称为银行和其他这样的词,这可能意味着从一个CPU到另一个不同的事情),其中每个页面是64kb。 然后它将有一个“页面”寄存器,必须先设置,在寻址扩展内存之前。 同样,从扩展内存的子例程调用/返回时,它也会有特别的指示。

为了使C编译器在处理这种扩展内存时生成正确的CPU指令,发明了非标准的nearfar关键字。 因为它们不是C标准中规定的非标准的,但是它们是事实上的行业标准,几乎每个编译器都以某种方式支持它们。

far指位于扩展内存中的存储器,超出地址总线的宽度。 由于它指的是地址,所以在声明指针时通常使用它。 例如: int * far x; 意思是“给我一个指向扩展内存的指针”。 编译器会知道它应该生成访问这些内存所需的特殊指令。 类似的,使用far函数指针会产生特殊的指令来从扩展内存跳转/返回。 如果你没有使用far你会得到一个指向正常的,可寻址的内存的指针,你最终会指向完全不同的东西。

near主要包括与一致和far ; 它指的是可寻址内存中的任何东西,相当于一个普通的指针。 所以它主要是一个无用的关键字,除了一些罕见的情况下,你要确保代码放在标准的可寻址内存中。 然后你可以明确地标记一些near东西。 最典型的情况是编写中断服务程序的低级硬件编程。 它们由一个固定宽度的中断向量通过硬件调用,与地址总线宽度相同。 这意味着中断服务程序必须位于标准的可寻址存储器中。


far最有名的应用也许就是上面提到的老MS DOS电脑了,现在这个电脑被认为是相当古老的,因此也很温和。

但是这些关键字也存在于更现代的CPU上! 最值得注意的是,在市场上几乎每8位和16位微控制器系列存在的embedded式系统中,这些微控制器通常具有16位的地址总线宽度,但是有时超过64kb的存储器。

只要你有一个CPU需要寻址超出地址总线宽度的内存,你将需要far 。 一般来说,这样的解决scheme是不被接受的,因为编写它们是相当痛苦的,并且总是考虑到扩展的内存。

推动64位PC发展的主要原因之一就是32位个人电脑已经到了内存使用开始达到地址总线限制的地步:他们只能寻址4Gb的内存。 2 ^ 32 = 429亿字节= 4Gb。 为了能够使用更多的RAM,这些选项不是像在DOS时期就是要求一些繁重的扩展内存解决scheme,或者是将计算机(包括它们的地址总线)扩展到64位。

指针基本上保存地址。 众所周知,英特尔内存pipe理分为4个部分。 所以当一个指针指向的地址在同一个段内时,它就是一个近指针,因此它只需要2个字节的偏移量。 另一方面,当一个指针指向一个超出该段的地址(这意味着在另一个段),那么这个指针是一个远的指针。 它由4个字节组成:两个分段,两个偏移量。

四个寄存器用于指代16位x86分段存储器体系结构中的四个段。 DS(数据段),CS(代码段),SS(堆栈段)和ES(额外段)。 该平台上的逻辑地址是写入段:hex的偏移量。

近指针指向(作为偏移量)当前段。

远指针使用段信息和偏移来指向段。 因此,要使用它们,DS或CS必须更改为指定的值,内存将被解除引用,然后恢复DS / CS的原始值。 请注意,它们的指针算术不会修改指针的段部分,所以溢出的偏移量就会包裹它。

然后是巨大的指针,这些指针被标准化为具有给定地址的最高可能段(与远指针相反)。

在32位和64位体系结构中,内存模型使用不同的分段,或根本不使用分段。

那么在DOS下,处理寄存器是有趣的。 和细分。 所有关于RAM的最大计数能力。

今天,这几乎是无关紧要的。 所有你需要阅读的是关于虚拟/用户空间和内核的差异。

由于win nt4(当他们从* nix偷取创意时),微软程序员开始使用所谓的用户/内核内存空间。 并从此避免直接访问物理控制器。 从那时起,一个处理直接访问内存段的问题也就消失了。 – 通过操作系统,一切都变成了R / W。

但是,如果你坚持理解和操作远近指针,看看linux内核源代码,以及它是如何工作的,那么我猜你会更新。

如果您仍然需要在DOS中使用CS(代码段)/ DS(数据段)。 看看这些:

https://en.wikipedia.org/wiki/Intel_Memory_Model http://www.digitalmars.com/ctg/ctgMemoryModel.html

我想在Lundin的下面指出完美的答案。 我懒得回答正确。 伦丁给了非常详细和明智的解释“竖起大拇指”!