Mic*_*kis 42
在16位x86分段存储器架构上,四个寄存器用于指代各自的段:
编写此体系结构的逻辑地址segment:offset
.现在回答这个问题:
近指针指向当前段(作为偏移量).
远指针使用段信息和偏移量来指向段.因此,要使用它们,必须将DS或CS更改为指定值,将取消引用内存,然后恢复DS/CS的原始值.请注意,它们上的指针算法不会修改指针的段部分,因此溢出偏移量只会将其包裹起来.
然后有巨大的指针,它们被规范化以具有给定地址的最高可能段(与远指针相反).
在32位和64位体系结构中,内存模型使用不同的段,或者根本不使用段.
Lun*_*din 36
由于没有人提到DOS,让我们忘记旧的DOS PC电脑,并从一般的观点来看待这一点.然后,非常简化,它是这样的:
任何CPU都有一个数据总线,这是CPU在一条指令中可以处理的最大数据量,即等于其寄存器的大小.数据总线宽度以位:8位,或16位或64位等表示.这是术语"64位CPU"的来源 - 它指的是数据总线.
任何CPU都有一个地址总线,也有一个以位表示的某个总线宽度.CPU可以直接访问的计算机中的任何存储器单元都具有唯一的地址.地址总线足够大,可以覆盖您拥有的所有可寻址内存.
例如,如果计算机具有65536字节的可寻址内存,则可以使用16位地址总线覆盖这些内存,2 ^ 16 = 65536.
大多数情况下,但并非总是如此,数据总线宽度与地址总线宽度一样宽.如果它们具有相同的大小是很好的,因为它保持CPU指令集和为其编写的程序更清晰.如果CPU需要计算一个地址,那么很方便该地址是否足够小以适应CPU寄存器(通常在地址时称为索引寄存器).
非标准的关键字far
,并near
用于描述在需要解决的内存超出了正常的CPU地址总线宽度系统指针.
例如,具有16位数据总线的CPU也可以方便地具有16位地址总线.但是同一台计算机可能还需要超过2 ^ 16 = 65536字节= 64kb的可寻址内存.
然后,CPU通常会有特殊指令(稍微慢一些),这使得它可以处理超过64kb的内存.例如,CPU可以将其大内存划分为n
页面(有时也称为库,段和其他此类术语,这可能意味着从一个CPU到另一个CPU的不同),其中每个页面为64kb.然后它将有一个"页面"寄存器,必须首先设置,然后才能寻址扩展内存.类似地,当从扩展内存中的子例程调用/返回时,它将具有特殊指令.
为了使C编译器在处理这种扩展内存时生成正确的CPU指令,发明了非标准near
和far
关键字.非标准,因为它们没有被C标准规定,但它们是事实上的行业标准,几乎每个编译器都以某种方式支持它们.
far
指位于扩展存储器中的存储器,超出地址总线的宽度.由于它指的是地址,因此通常在声明指针时使用它.例如:int * far x;
表示"给我一个指向扩展内存的指针".然后编译器将知道它应该生成访问这种内存所需的特殊指令.类似地,使用的函数指针far
将生成跳转到/从扩展内存返回的特殊指令.如果你没有使用far
那么你会得到一个指向正常,可寻址内存的指针,你最终会指向完全不同的东西.
near
主要包括与far
; 它指的是可寻址存储器中的任何东西,它等同于常规指针.所以它主要是一个无用的关键字,除了一些罕见的情况,你想确保代码放在标准的可寻址内存中.然后你可以明确标记为near
.最典型的情况是低级硬件编程,您可以在其中编写中断服务程序.它们由硬件从具有固定宽度的中断向量调用,该宽度与地址总线宽度相同.这意味着中断服务程序必须位于标准可寻址存储器中.
最着名的使用far
和near
可能是提到的旧MS DOS PC,现在被认为是相当古老的,因此有轻微的兴趣.
但这些关键字也存在于更现代的CPU上!最值得注意的是在他们的几乎每8位和16位微控制器系列在市场上存在,因为这些微控制器通常具有16位地址总线宽度,但有时大于64KB的内存多的嵌入式系统.
每当你有一个CPU需要寻址超出地址总线宽度的内存时,你就需要far
和near
.一般来说,这样的解决方案是不受欢迎的,因为对它们进行编程并且总是考虑扩展内存是非常痛苦的.
推动开发64位PC的主要原因之一,实际上是32位PC已经达到其内存使用量开始达到地址总线限制的程度:它们只能解决4Gb的RAM问题.2 ^ 32 = 4,29亿字节= 4Gb.为了能够使用更多的RAM,这些选项要么采用像DOS时那样繁琐的扩展内存解决方案,要么将计算机(包括地址总线)扩展到64位.