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

时间:2009-11-17 16:06:46

标签: c pointers

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

6 个答案:

答案 0 :(得分:42)

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

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

此架构上的逻辑地址写为segment:offset。现在回答这个问题:

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

  • 远端指针使用段信息和偏移量来指向段。因此,要使用它们,必须将DS或CS更改为指定值,将取消引用内存,然后恢复DS / CS的原始值。请注意,对它们的指针运算不会修改指针的段部分,因此溢出偏移量只会将其包裹起来。

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

在32位和64位架构上,内存模型使用不同的段,或者根本不使用。

答案 1 :(得分:33)

由于没有人提到DOS,让我们忘记旧的DOS PC电脑,并从一般的观点来看这个。然后,非常简化,它是这样的:

任何CPU都有一条数据总线,这是CPU在一条指令中可以处理的最大数据量,即等于其寄存器的大小。数据总线宽度以位表示:8位,或16位,或64位等。这是术语" 64位CPU"来自 - 它指的是数据总线。

任何CPU都有一个地址总线,也有一个以位表示的某个总线宽度。 CPU可以直接访问的计算机中的任何存储器单元都具有唯一的地址。地址总线足够大,可以覆盖您拥有的所有可寻址内存。

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

大多数情况下,但并非总是如此,数据总线宽度与地址总线宽度一样宽。如果它们具有相同的大小是很好的,因为它保持CPU指令集和为其编写的程序更清晰。如果CPU需要计算一个地址,那么很方便该地址是否足够小以适应CPU寄存器(通常在地址时称为索引寄存器)。

非标准关键字farnear用于描述您需要处理超出正常CPU地址总线宽度的内存的系统上的指针。

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

然后,CPU通常会有特殊指令(稍慢),这使得它可以处理超过64kb的内存。例如,CPU可以将其大内存划分为n (有时也称为银行和其他此类术语,这可能意味着从一个CPU到另一个CPU的不同之处),每个页面都是64kb。然后会有一个"页面"在寻址扩展内存之前,必须首先设置的寄存器。类似地,当从扩展内存中的子例程调用/返回时,它将有特殊指令。

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

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

near主要用于与far保持一致;它指的是可寻址存储器中的任何东西,它等同于常规指针。所以它主要是一个无用的关键字,除了一些罕见的情况,你想确保代码放在标准的可寻址内存中。然后,您可以将某些内容明确标记为near。最典型的情况是低级硬件编程,您可以在其中编写中断服务程序。它们由硬件从具有固定宽度的中断向量调用,该宽度与地址总线宽度相同。这意味着中断服务程序必须位于标准可寻址存储器中。

farnear最着名的用法可能是提到的旧的MS DOS PC,现在被认为是相当古老的,因此引起了人们的兴趣。

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

如果您的CPU需要处理超出地址总线宽度的内存,则需要farnear。一般来说,这样的解决方案是不受欢迎的,因为对它们进行编程并且总是考虑扩展内存是非常痛苦的。

推动开发64位PC的一个主要原因实际上是32位PC已经达到了内存使用量开始达到地址总线限制的程度:它们只能解决4Gb问题RAM。 2 ^ 32 = 4,29亿字节= 4Gb。为了能够使用更多RAM,这些选项要么采用像DOS时那样繁琐的扩展内存解决方案,要么将计算机(包括地址总线)扩展到64位。

答案 2 :(得分:22)

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

我认为它们与现代平台无关。但是你可以了解它们herehere(正如其他答案所指出的那样)。基本上,指针是扩展计算机中可寻址内存的一种方法。 I.E.,在16位平台上处理超过64k的内存。

答案 3 :(得分:4)

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

答案 4 :(得分:0)

四个寄存器用于指代16位x86分段存储器架构上的四个段。 DS(数据段),CS(代码段),SS(堆栈段)和ES(额外段)。此平台上的逻辑地址写为segment:offset,以十六进制表示。

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

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

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

在32位和64位架构上,内存模型使用不同的段,或者根本不使用。

答案 5 :(得分:0)

在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。我太懒了,无法正确回答。伦丁给出了非常详细和明智的解释"竖起大拇指"!