C 的内存模型及其对指针算术等的使用,似乎是对平面地址空间进行建模。16 位计算机使用分段内存访问。16位C编译器如何处理这个问题并从C程序员的角度模拟平面地址空间?例如,以下代码在 8086 上大致会编译成什么汇编语言指令?

long arr[65536];  // Assume 32 bit longs.
long i;
for(i = 0; i < 65536; i++) {
    arr[i] = i;
}
有帮助吗?

解决方案

16位C编译器如何处理此问题并从C程序员的角度模拟平坦的地址空间?

他们没有。相反,他们使分段对 C 程序员可见,通过使用多种类型的指针来扩展语言: near, far, , 和 huge. 。A near 指针只是一个偏移量,而 farhuge 指针是段和偏移量的组合。有一个编译器选项可以设置 记忆模型, ,它确定默认指针类型是近还是远。

即使在今天,在 Windows 代码中,您也会经常看到类似的 typedef LPCSTR (为了 const char*)。“LP”是 16 位时代的遗留物;它代表“长(远)指针”。

其他提示

C内存模型没有以任何方式暗示平面地址空间。它从来没有。事实上,C语言规范是专门设计用来允许非平坦地址空间。

在最简单的实现具有分段的地址空间,最大连续对象的大小将由段(一个16位的平台上的65536个字节)的大小的限制。这意味着,在size_t这样的实现将是16比特,并且您的代码根本不会编译,因为你正在试图宣布具有比允许的最大尺寸较大的对象。

一个更复杂的实施将支持所谓的巨大的内存模型。你看,没什么寻址的上的分段式内存模型中的任何的大小,它只是需要在指针算术一些额外的努力,连续的内存块没问题。因此,巨大的内存模型中,实施将使这些额外的努力,这将使得代码慢一点,但同时将允许处理几乎任何大小的物体。所以,你的代码将编译完全正常。

在真正的16位的环境下使用16个指针到达其任何地址。例子包括PDP-11,6800家族(6802,6809,68HC11),并且8085.这是一个清洁和高效的环境,就像一个简单的32位架构。

在80x86家族强加于我们在所谓的“实模式” -the天然8086混合16位/ 20位的地址空间寻址空间。通常的机制来处理,这是增强类型的指针为两个基本类型,near(16位指针)和far(32位指针)。代码和数据的指针的默认可以本体由一个“存储模式”被设置:tinysmallcompactmediumfar,和huge(一些编译器不支持所有型号)

tiny存储器模型是小程序在其整个空间(代码+数据+栈)小于64K是有用的。所有的指针是(默认)16位或near;指针隐含地与对整个程序段值相关联。

small模型假定数据+堆栈是小于64K并且以相同的段;代码段仅包含代码,所以最多能有64K为好,为128K的最大内存占用量。代码指针near和含蓄与CS(代码段)有关。数据指针也near并用DS(数据段)相关联。

medium模型具有最多数据+堆栈(类似小)的64K,但可以具有代码的任何量。数据指针是16位,并且隐含地联系在一起的数据段。代码指针是32位的指针far并具有段值取决于接头是如何设置的代码组(一个难吃簿记麻烦)。

compact模型是介质的补体:小于64K代码,但任何数量的数据。数据指针是far和代码指针near

largehuge模型,指针的默认子类型是32位或far。主要的区别是巨大的指针总是会被自动归一化,使增加他们避免了64K包变通的问题。见

在DOS16位,我不记得当时能够做到这一点。你可以有个事情,每一64K(bytes)(因为该段可以调节和偏零),但不记得如果你可以越过边界与一个单一的阵列。平存空间,你可以威利愿意不愿意拨出任何你想要的,并达到作为深为你喜欢入一系列没有发生直到我们可以汇编32位DOS程序(在386或486处理器).也许其它的操作系统编译器比其他微软和borland可能会产生平面阵列大于64kbytes.Win16我不记得自由,直到win32的打击,也许我的记忆是生锈...你是幸运还是富有兆字节的记忆无论如何,一个256kbyte或512kbyte机不是闻所未闻的。你的软盘驱动器,有几分之一梅格到1.44meg最终,你的硬盘,如果任何已经有十几个或几梅格,所以你才没有计算的事情,之大,经常。

我记得我的特别挑战我必须学习有关DNS当你可以下载整个DNS数据库中所有注册域名的地球上,事实上你已经把你自己的dns server这几乎是时需要有一个网站。该文件是35megabytes,我的硬盘是100megabytes,再加上dos和windows嚼一些。可能有1或2meg的存储器中,可能已经能够做到的32位dos程序的时间。一部分如果是我想要分析的ascii文件,该文件我在多次,但每个过程的输出不得不去到另一个文件,我不得不要删除现有文件的房间盘上的下一文件。两个磁盘控制器上的一个标准的主板,一个硬盘和光盘驱动器,在这里再次这东西不是廉价的,没有很多备用isa槽如果你能买得起的另一个硬盘和磁盘控制器的卡片。

甚至还有问题的阅读64kbytes C您通过了fread字节的数量你想读的16位int,这意味着0至65535不65536字节,并表现急剧下降,如果你没有阅读甚至大部门所以你只要读32kbytes的时间发挥最大效能, 64k没来直到进入dos32天,当你是最后深信,价值传递给fread现在是一个32位数目和编译器不要砍掉高16位和只使用较低的16位(其中经常发生,如果你用足够的编纂者/版本)。目前,我们正在遭受类似问题的32位的64个过渡,因为我们没有与16至32位的过渡。什么是最有趣的是代码的人像我一样了解到,打算从16到32位int改变了大小,但unsigned char和unsigned long没有,所以你适应的和很少使用int使你的计划将编制和工作对两16和32位。(代码从人们从这一代人类站出来为其他人也生活,通过它,并采用同样的欺骗).但32至64过渡是周围的其他方式和代码不重构使用uint32类型声明的痛苦。

阅读wallyk的答复,只是进来了巨大的指的事情缠不会敲响了警钟,也不总是能够编制用于巨大的。小是平存储器模型中,我们都舒服的今天,作为与今天很容易因为你没有担心的分段。所以这是一个微弱的汇编小时你可以。你还没有大量的存储器或磁盘或软的空间所以你只是没有通常处理的数据,大。

并同意与另一个答案,该段的偏移的事情是8088/8086英特尔。整个世界尚未由英特尔,所有其他平台,只有一台存储空间、或使用其他的技巧,也许是在硬件(外部处理器)要解决的问题。因为该段中/偏英特尔能够最16位件事超过它也许应该拥有的。段中/偏移了一些很酷的和有趣的事情你可以用它做的,但它是尽可能多的痛苦,因为其他任何东西。你要么简化你的生活,并生活在一个平坦的存储空间或者你不断担心段边界。

真的牵制旧的x86的地址大小的排序棘手。可以说,它的16位,因为算术,你可以在地址执行必须符合一个16位的寄存器。你也可以说,这是32位的,因为实际地址计算抵抗16位通用寄存器和16位段寄存器(所有32位显著)。你也可以只说这是20位的,因为段寄存器左移,并添加到GP寄存器硬件寻址4位。

这其实不要紧,其中大部分的这些,你选择了,因为他们是C抽象机的所有基本相当近似之一。有些编译器让你选择你使用每个编译内存模型,而其他人只是假设32个地址,然后仔细检查操作,可能溢出16位发出指令,处理这种情况正常。

查核的维基百科条目。关于远指针。基本上,其可以指示一个段和偏移,从而能够跳转到另一个段。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top