2014-01-07 20:18:51 +0000 2014-01-07 20:18:51 +0000
369
369
Advertisement

如果32位的机器只能处理2^32以下的数字,为什么我写1000000000000(万亿)而不至于死机?

Advertisement

32位的计算机只能存储231 - 1以下的有符号的整数,这就是为什么我们的IPv4地址已经用完了,进入了64位时代。

Advertisement

答案 (18)

784
784
784
2014-01-07 20:31:38 +0000

我回答你的问题是问你一个不同的问题:

如何用手指数到6?

你很可能用一只手数到最大的数字,然后当你的手指用完了,你就用第二只手去数。计算机也是这样做的,如果他们需要表示一个比单个寄存器所能容纳的值大的值,他们会使用多个32位块来处理数据。

395
395
395
2014-01-07 20:36:34 +0000

你是正确的,32位整数不能持有大于2^32-1的值。但是,这个32位整数的值和它在你的屏幕上的显示方式是完全不同的。打印出来的字符串 “1000000000000 "在内存中并不是由32位整数来表示的。

要从字面上显示数字 "1000000000000 "需要13个字节的内存。每个字节最多可以容纳255个值。其中没有一个可以容纳整个数字值,但单独解释为ASCII字符(例如,’0‘字符由十进制值48表示,二进制值00110000),它们可以被串联成对你这个人类来说有意义的格式。就像上面的例子一样,它可以被解释为一个数值、一个字符,甚至是其他完全不同的东西。虽然一个32位整数可能无法容纳1000000000000的值,但一个32位的浮点数字却可以,使用完全不同的解释。

至于计算机内部如何处理和处理大的数字,有64位整数(可以容纳高达160亿的值)、浮点值,以及可以处理任意大的数字的专门库。

190
Advertisement
190
190
2014-01-07 21:37:16 +0000

首先,也是最重要的,32位计算机可以在一个机器字中存储最多2³²-1的数字。机器字](https://en.wikipedia.org/wiki/Machine_word)是指CPU自然可以处理的数据量(即对这种大小的数据进行操作,一般是在硬件中实现的,一般是最快的)。32位CPU使用的是由32位组成的字,因此在一个字中可以存储从0到2³²-1的数字**。

其次,1万亿1000000000000是两码事

  • 1万亿是一个抽象的数字概念
  • 100000000是文字

通过按一次1,再按12次0,就是在打文字。1输入1,0输入0。看到了吗?你输入的是字符。字符不是数字。打字机根本没有CPU或内存,他们对这种 “数字 "的处理很好,因为它只是文字。

证明10000000000000000不是数字,而是文字:*它可以表示1万亿(十进制),4096(二进制)或281474976710656(十六进制)。在不同的系统中,它的含义更多。10000000000000000的含义是一个数字,而存储它是另一回事(我们稍后再谈)。

要存储文本(在编程中称为string)1000000000000,你需要14个字节(每个字符一个,再加上一个终止的NULL字节,基本上意味着 "字符串到此为止”)。这就是4个机器字。3个半就足够了,但正如我所说,对机器字的操作是最快的。让我们假设ASCII用于文本存储,那么在内存中会是这样的:(将01对应的ASCII码转换为二进制,每个字都在一个单独的行中)

00110001 00110000 00110000 00110000
00110000 00110000 00110000 00110000
00110000 00110000 00110000 00110000
00110000 00000000 00000000 00000000

4个字符适合一个字,其余的移到下一个字。剩下的移到下一个字中,直到所有的字符(包括第一个NULL字节)都适合。它的工作原理和溢出的文本一样,但是它们是从右到左的拟合。这听起来可能很复杂,所以这里有一个例子。为了简单起见,让我们假设:

  • 我们想象中的计算机使用十进制而不是二进制
  • 一个字节可以存储数字 0..9
  • 一个字由两个字节组成

这里是一个空的2字存储器。

0 0
0 0
0 4
0 0

让我们存储数字4:

1 3
0 0

现在让我们添加9:

9 9
0 0

注意,两个运算符都可以在一个字节内,但结果不适合。但是我们还有一个可以使用的。现在让我们存储99:

0 0
0 0

再一次,我们用第二个字节来存储数字。让我们加1:

0 0
9 9

哎呀…..。这就是所谓的整数溢出,是很多严重问题的原因,有时会导致非常昂贵的问题

但如果我们预计会发生溢出,我们可以这样做:

0 1
0 0
0099 | +1
0100

现在加上1:

00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111 | +1
00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000000

如果去掉字节分隔符和换行符,就会变得更清晰:

&001

我们已经预测到溢出可能会发生,我们可能需要额外的内存。这样处理数字的速度并不像处理适合单字的数字那样快,必须在软件中实现。在32位CPU中加入对2-32位字数的支持,可以有效地使它成为64位CPU(现在它可以在64位数字上运行,对吗?(但它在十六进制的情况下工作得很好)

40
40
40
2014-01-07 23:06:37 +0000

你也可以写出“This STATEMENT IS FALSE”而不至于让你的电脑崩溃:) @Scott的答案对某些计算框架来说是正确的,但是你关于 “写 "一个大的数字的问题意味着它只是普通的文本,至少在被解释之前是这样的。我将用高抽象的方式来描述这些,也就是说,现代程序员在将代码翻译成机器代码执行之前,可能会用现代程序员编写的术语来描述。

计算机上的数据必须被限制在一定的类型上,而计算机对这种类型的定义描述了可以对这些数据进行哪些操作以及如何操作(即比较数字、串联文本或XOR布尔)。你不能简单地把文本加到一个数字上,就像你不能把一个数字乘以文本一样,所以这些值类型之间可以进行一些转换。

我们先来看看无符号整数。在这些值类型中,所有的位都是用来存储数字信息的;你的是一个32位无符号整数的例子,可以存储从02^32-1的任何值。是的,根据语言或平台的架构,你可以使用16位整数或256位整数。直观地讲,有符号的整数是游戏的名称。惯例是将所有的值从-2^(n-1)分配到2^(n-1)-1—-这样我们就可以避免处理+0-0两种写法的混乱。因此,一个32位有符号的整数将持有一个从-21474836482147483647的值。

好了,我们已经介绍了整数,整数是没有小数成分的数字。表达这些数字比较棘手:非整数部分只能在01之间,所以每增加一个额外的位来描述它,就会增加它的精度:1/2,1/4,1/8…… 问题是,你不能把一个简单的小数0.1精确地表达为分母中只能有2的分母的小数之和! 如果把这个数字存储为整数,但同意把半径(小数)的点放在这里不是更容易吗?这就是所谓的fixed point数,在这里我们存储1234100,但同意将其读成1234.100。它的工作方式非常巧妙,它用一个位来存储符号值,然后用一些位来存储指数和意义。有一些标准来定义这样的分配,但是对于一个_32位浮点数来说,你可以存储的最大数字是

(2 - 2^-23) * 2^(2^7 - 1) ≈ 3.4 * 10^38

,但是这是以精度为代价的。浏览器中的JavaScript使用64位浮点数,它仍然无法实现。只需将此复制到地址栏中,然后按回车键。

javascript:alert(0.1+0.2);

&001

还有更多的替代类型,比如Microsoft .NET 4.5的floating point ,理论上它没有上下限,必须以 "分批 "的方式计算;但更吸引人的技术可能是那些能理解数学的技术,比如Wolfram Mathematica引擎,它可以精确地处理抽象的值,比如无穷大

31
Advertisement
31
31
2014-01-07 21:58:50 +0000

诚然,如果计算机坚持使用一个简单的二进制数字表示方式来存储数字(在32位系统上是4个字节),那么32位计算机最多只能存储2^32的数字。但有很多其他的方法来编码数字,这取决于你想用它们来实现什么。计算机可以使用各种不同的方式来编码。标准IEEE 754定义了对大于2^32的数字进行编码的规则。粗略地讲,计算机可以通过将32位分成不同的部分来实现,这些部分代表着数字的某些数字,其他的部分代表着数字的大小(即指数,10^x)。这使得数字在大小方面的范围大得多,但在精度上有所妥协(这在很多用途上是可以的)。当然,计算机也可以用一个以上的字来编码,这样可以增加可用的编码数字的大小精度。IEEE标准的简单的十进制32版本允许精度约为7位小数点后的数字和大小约为10^96的数字。很明显,你可以在编码中使用更多的字数,而不受限制(虽然在转换为编码格式的时候会有一个性能上的损失)。如果你想探索一种可以实现的方法,有一个很好的开源插件,它使用了一种编码方案,允许在计算中使用数百位数的精度。这个插件叫做Xnumbers,可以在这里中找到。它的代码是用Visual Basic编写的,虽然不是最快的,但它的优点是容易理解和修改。它是学习计算机如何实现对较长的数字进行编码的好方法。你可以在Excel中玩转结果,而不需要安装任何编程工具。

24
24
24
2014-01-07 23:47:36 +0000

这都是你的问题。

你可以在纸上_写出你喜欢的任何数字。试着在一张白纸上写上一万亿个点。这是很慢的,而且没有效果的。这就是为什么我们有一个10位数系统来表示这些大数字。我们甚至有 “百万"、"万亿 "等大数字的名字,所以你不会大声说one one one one one one one one one one one...

32位处理器的设计是为了让内存块的长度正好是32位二进制数的内存块工作得最快速有效。但我们人类通常使用10位数的数字系统,而计算机作为电子计算机,使用的是2位数系统二进制)。数字32和64刚好是2的次方,100万和1万亿也是10的次方。比如说,我们用这些数字操作起来比用65536的万位数更容易。

我们把大的数字写在纸上的时候,会把大的数字分解成数字。而计算机则把数字分解成更多的数位数。我们可以写下我们喜欢的任何数字,计算机也可以这样设计。

15
Advertisement
15
15
2014-01-08 00:42:45 +0000

32位和64位指的是内存地址。你的电脑内存就像邮筒一样,每一个都有不同的地址。CPU(中央处理单元)利用这些地址来寻址你的RAM(随机存取内存)上的内存位置。当CPU只能处理16位地址的时候,你只能使用32MB的RAM(当时看起来很庞大)。32位的时候,你只能使用32MB的内存(当时看来是很庞大的)。现在,我们有了64位地址,RAM就变成了3TB(当时看起来很大)。 然而,程序可以分配多个内存块来存储数字和文本,这取决于程序,而与每个地址的大小无关。所以一个程序可以告诉CPU,我要用10个地址块的存储,然后存储一个很大的数字,或者是10个字母字符串什么的。 侧面说明:内存地址是由 “指针 "指向的,所以32位和64位的值是指用来访问内存的指针的大小。

13
13
13
2014-01-08 06:44:38 +0000

因为显示数字是用单个字符来表示,而不是整数。每个数字中的每个数字都用一个独立的字符来表示,其整数值由所使用的编码决定,例如'a'用ascii值97表示,而'1'49表示。在这里查看ascii表。 对于显示'a'和'1'都是一样的。它们是字符字形,而不是整数。在32位的平台上,每个字符的最大值是255(8位或1个字节大小)。它们能显示多少独立的字符取决于你的RAM。如果你只有1字节的RAM,那么你只能显示一个字符,如果你有1GB的RAM,你可以显示1024个1024个1024个字符(太懒了,无法计算)。虽然它与计算机的bit-size不完全相关,但对标准有一定的影响。当IPV4标准创建时,他们将IP值存储为32位整数。现在一旦你给了大小,它就成了标准。我们对互联网的一切了解都依赖于此,然后我们就没有了可以分配的IP地址。因此,如果IP标准被修改为64位,所有的东西都会停止工作,包括你的路由器(我认为这是正确的)和其他网络设备。所以必须创建一个新的标准,把32位的整数换成128位。并调整了标准的其余部分。硬件厂商只需要声明支持这个新标准,就会得到病毒式的传播。虽然没有那么简单,但我想你应该明白了这里的意思。

免责声明:这里提到的大部分观点都是我的假设。为了简单化,我这里可能漏掉了一些重要的点。我不擅长数字,所以一定是漏掉了一些数字,但我在这里的重点是回答OP的回答,为什么不会死机。

13
Advertisement
13
13
2014-01-08 11:27:08 +0000

在处理器中,有 “字"。有不同的词。人们说 "32位处理器 "时,多指 "内存总线宽度"。这个词由不同的 "字段 "组成,指的是计算机的子系统,分别对应于传输(24位)和控制(其他位)。准确的数字我可能是错误的,请你自己通过说明书来确定。

完全不同的是计算。SSE和MMX指令集可以存储长整数。

目前的Opteron处理器可以处理256位宽的数字(我不确定是整数,但可以肯定是float)。(1)总线宽度与计算宽度没有直接联系,(2)即使是不同的字(内存字、寄存器字、总线字等)之间也没有联系,除此之外,它们之间有共同的除法,大约是8或16或24。许多处理器甚至使用6位字(但它的历史)。

10
10
10
2014-01-08 20:39:13 +0000

一般来说,计算设备的目的是接受、处理、存储和发射数据。底层硬件只是一台帮助执行这四种功能的机器。

软件是告诉机器如何接受数据,如何处理数据,如何存储数据,以及如何将数据提供给其他人的代码。在32位机器的情况下,处理数据的寄存器大多只有32位宽。但这并不意味着机器不能处理超过2^32的数字,这意味着如果你想处理更大的数字,机器可能需要一个以上的周期来接受它,处理它,存储它,或发出它。

软件告诉机器如何处理数字。如果软件是为了处理大数字而设计的,它就会向CPU发送一系列指令,告诉它如何处理较大的数字。例如,你的数字可以用两个32位寄存器来表示。如果你想在你的数字上加1,234,软件会告诉CPU首先将1,234加到下位寄存器中,然后检查溢出位,看看这个加法是否导致下位寄存器的数字过大。

就像小学生被教导的用携带式加法一样,CPU可以被告知要处理大于单个寄存器所能容纳的数字。对于大多数通用的数学运算,对于任何实际大小的数字都是如此。

8
Advertisement
8
8
2014-01-09 15:18:54 +0000

32位计算机在一个机器字中最多只能存储2^32的数字,但这并不意味着它不能处理更大的数据实体。

一般来说,32位计算机的意义在于数据总线和地址总线是32位宽的,这意味着计算机可以一次处理4GB的内存地址空间,通过数据总线一次发送4个字节的数据。

不过,这并不限制电脑处理更多的数据,它只需要在数据总线上发送数据时,将数据分成4个字节的大块。

你可以在计算机中处理比这大得多的数字,但这时的计算必须由软件来完成,CPU没有处理大于128位的数字的指令。(它可以以浮点数字的形式处理更大的数字,但那时你只有15位的精度)。

6
6
6
2014-01-10 19:11:43 +0000

只是在其他很多答案中补充说明一下,因为这个问题中有一个相当重要的事实被忽略了。它与寄存器大小没有任何关系。很多32位的CPU很可能有64位甚至128位的寄存器。特别是指x86产品线,最近的消费级CPU,都是64位的,为了特殊的目的,都拥有高达256位的寄存器。

这种寄存器宽度和地址宽度的区别,从古时候就已经存在了,当时我们有4位寄存器和8位地址,反之亦然。

其实很简单,不管寄存器的大小,存储一个大的数字是没有问题的,这一点在其他答案中已经解释过了。

寄存器,不管大小,也可以额外计算大的数字的原因是,太大的计算可以分解成几个小的计算,而这些小的计算确实可以装进寄存器中(实际上只是稍微复杂一点)。

6
Advertisement
6
6
2014-01-10 21:36:01 +0000

已经给出的答案其实都很好,但它们往往从不同的方面来解决这个问题,因此呈现出了一个不完整的画面。在我看来,他们也有点过于技术化了。

所以,只是为了澄清一些在其他答案中暗示过但没有明确表达的东西,我认为这是问题的关键:

**你在你的问题中混淆了几个概念,其中一个("32位")实际上可以指各种不同的东西(不同的答案有不同的解释)。这些概念都与不同的计算环境中使用(或可用的)比特数(1和0)有关(我的意思是希望下面的例子能澄清),但这些概念是其他方面不相关的。IPv4和IPv6之间的主要区别(至少是最著名的区别)是,IPv6中的地址空间(即可用于区分网络上不同位置的地址集)较大。这与每一个数据包中的数据包有多少个位元被分配给(即预留出来的目的)来识别数据包的发送者和接收者有关。每个数据包就像通过蜗牛邮件发送的信件,而地址空间就像你在信封上写地址和回信地址时 “允许 "使用的字符数。 - 我没有看到其他答案中提到这一点。 –非计算机的类比:单词可以被认为有点像字母组成纸上的文字,甚至可以被认为是思维中的单个单词。 - 参见Guffa的回答sanaris的回答,以及gronostaj的回答的第一段。指针是计算机在内存中记录任意数据块的位置的最底层方式。需要注意的是,计算机(或者说操作系统)使用的指针大小限制了单个指针可以访问的内存范围,因为一个指针可以 "指向 "的内存位置的可能数量和指针本身的可能值一样多。这类似于IPv4限制了互联网地址的范围,但并没有限制数据的数量,例如,一个特定的网页。然而,指针的大小并不_限制指针所指向的数据本身的大小。(关于允许数据大小超过指针范围的方案的一个例子,请看Linux的inode指针结构。注意,这是对 "指针 "这个词的使用与典型的用法略有不同,因为指针通常指的是指向随机存取内存的指针,而不是指硬盘空间) –非计算机类比:嗯嗯………..这个有点棘手。也许杜威的十进制系统用于索引图书馆资料的索引系统有点类似?或者是任何索引系统,真的。 –参见SiteNook的回答。 –请注意,我在上面对指针的解释中,掩盖了一些微妙的细节,可以说是不完全正确的。然而,在程序员直接用指针工作的编程语言中,我所画的心智模式通常足以满足实用目的。 - 计算机 "能够显示 "的*不受计算机的硬件或操作系统的限制,它们被像对待其他文本一样对待。 - 非计算机的类比:在纸上写字 - 参看用户1306322的回答Bigbio2002的回答

注意,这并不是对 "32位 "这个短语的全面解释列表。

5
5
5
2014-01-11 23:24:10 +0000

在你的脑海中,你只知道10个不同的数字。0到9的数字。在你的大脑内部,这肯定是和电脑中的编码方式不同。

计算机用位来编码数字,但这并不重要。这只是工程师们选择的编码方式,但你应该忽略这一点。你可以认为,32位的计算机有40多亿个不同的值,而我们人类有10个不同的值的唯一表示,

每当我们必须理解一个较大的数字时,我们就用一个系统。最左边的数字是最重要的。

一个能够区分40亿个不同值的计算机,同样地,在一组值中,最左边的值要比下一个值重要40亿倍。实际上,计算机根本就不在乎。它不会给数字分配 “重要性"。程序员必须制作特殊的代码来处理这个问题。

每当一个值变得大于唯一符号的数量,在人类的脑海中是9,你就会在左边的数字上加一个。除非计算机有一个系统来处理这个问题,否则它就会简单地写上0,忘记了还有一个额外的数字。幸运的是,计算机有一个 "溢出标志",在这种情况下,计算机就会升起一个 "溢出标志"。

3+3=6
``` ```
5+5=10. This situation is called an overflow.

你可能在学校里学过一个方法。一种算法。这个算法其实很简单。从最左边的两个符号开始加法。

987+321 is more difficult.
7+1=8, we now have ...8 as the result so far
8+2=10, the overflow flag is raised. We now have ...08, plus overflow.

然后换到下一个槽,进行同样的加法。

9+3=12, and then we add one due to overflow. ...308, and we had another overflow.
1308

既然有一个溢出,那就意味着我们要把1加到下一个数字上。

&001

&001

一台计算机的工作方式完全相同,只是它有2^32或更好的2^64个不同的符号,而不是像人类一样只有10个。幸运的是,对于程序员来说,这一点被抽象化了。位数只有两位数,因为这很容易用电源线来表示。要么是亮着,要么是关着。

最后,计算机可以把任何数字显示成简单的字符序列。这也是计算机最擅长的。而字符序列之间的转换算法,和内部表示法的转换是相当复杂的。

5
Advertisement
5
5
2014-01-11 17:59:58 +0000

如果你想知道一个典型的Linux系统上有多少程序处理大数处理和输出的实际例子:

libgmp - GNU多精度算术库是Linux系统上最广泛使用的库。一个简单的2^80乘以1000的例子:

#include <gmp.h>

// Each large integer uses the mpz_t type provided by libgmp
mpz_t a_large_number;
mpz_t base;
mpz_t result;

// Initalize each variable
mpz_init(a_large_number);
mpz_init(base);
mpz_init(result);

// Assign the number 2 to the variable |base|
mpz_set_ui(base, 2);

// Raise base^80 (2^80), store the result in |a_large_number|
mpz_pow_ui(a_large_number, base, 80);

// Multiply |a_large_number| by 1000, store the result in |result|
mpz_mul_ui(result, a_large_number, 1000);

// Finally, output the result in decimal and hex notation
gmp_printf("decimal: %Zd, hex: %ZX\n", result, result);

所以基本上和一般的+-*/操作符是一样的,只是用一个库来分解数字,并在内部存储为多个机器字大小(即32位)的数字。还有scanf()类型的函数,用于处理将文本输入转换为整数类型。

的结构和Scott Chamberlain的例子一样,就是用两只手数到6的例子。它基本上是一个机器字大小的mpz_t类型的数组,当一个数字太大,无法装入一个机器字时,GMP会使用多个mp_limb_t来存储数字的高/低部分。

5
5
5
2014-01-09 16:36:20 +0000

如果你在计算器中写1000000000000,计算机会将其计算为实数型数,并带有小数点。你提到的32位的限制触及到了更多的整数型数,而没有小数点。不同的数据类型使用不同的方法来获取位数/bytes。这个表可以帮助你抓住重点http://msdn.microsoft.com/en-us/library/296az74e.aspx )。这触及到了C++的限制。例如Int64类型数***有-922333372036854775808到9223372036854775807的限制。真实类型的数字包含有浮点指数*,你可以输入更大的数字,但精确度/精度有限。 http://msdn.microsoft.com/en-us/library/6bs3y5ya.aspx ) 例如,C++中的LDBL(大双倍)的最大指数为308,所以你可以输入或有一个结果数9.999 x 10^308,这意味着你理论上会有308(+1)位的9,但只有15个最重要的数字会被用来表示,其余的数字会丢失,因为精度有限。所以你可以想象,专业的应用程序可以处理比C++大得多的数字(和/或更精确/更精确)。

3
Advertisement
3
3
2014-01-12 00:41:20 +0000

因为你显示的不是一个数字(就计算机而言),而是一个字符串,或者是一串数字。当然,一些处理数字的应用程序(如计算器,我想),可以处理这样的数字,我想。我不知道他们用的是什么技巧…..。我相信其他的一些更详细的答案中,肯定会涉及到这个问题。

0
0
0
2016-12-30 11:54:31 +0000

这个答案的大部分内容最初来自于这个答案(在另一个问题被标记为重复之前写的)。所以我讨论的是使用8位的值(尽管这道题问的是32位的值),但是没关系,因为8位的值在概念上更容易理解,而且同样的概念也适用于32位的算术等较大的值。

当你把两个8位的数字相加,你能得到的最大的数字是(0xFF+0xFF=1FE)。事实上,如果你把两个8位的数字相乘,你能得到的最大的数字(0xFF * 0xFF = 0xFE01)仍然是16位,是8位的两倍。例如,8位处理器只能跟踪8位),这并不准确。8位处理器以8位为单位接收数据(这些 “块 "通常有一个正式的术语:"字")。在8位处理器上,使用的是8位字。在64位处理器上,可以使用64位字。)

所以,当你给计算机3个字节: 字节#1:MUL指令 字节#2:高阶字节(如0xA5) 字节#3:低阶字节(如0xCB) 计算机可以产生一个超过8位的结果。CPU可能会产生这样的结果: 0100 0000 0100 0010 xxxx xxxx xxxx xxxx xxxx 1101 0111 又名: 0x4082xxxxD7 现在,让我来为你解读一下: 0x只是表示下面的数字是十六进制。
我稍后再详细讨论一下 "40", 82是 "A "寄存器的一部分,是一串8位, xx和xx是另外两个寄存器的一部分,分别命名为 "B "寄存器和 "C "寄存器。我之所以没有把这些位填上0或1,是因为一个 "ADD "指令(发送到CPU)可能会导致这些位被指令改变(而我在这个例子中使用的其他大多数位可能会被改变,除了一些标志位之外)。寄存器内置在CPU中,所以CPU可以访问寄存器,而不需要与RAM棒上的内存交互。

所以0xA5乘以0xCB的数学结果就是0x82D7。

现在,为什么这些位会被拆分成A和D寄存器,而不是A和B寄存器,或者C和D寄存器呢?好吧,再来一次,这是我使用的一个示例场景,意在与真正的汇编语言(Intel x86 16位,如Intel 808080和8088以及许多较新的CPU所使用的16位)在概念上相当相似。可能会有一些共同的规则,比如 "C "寄存器通常被用作计数操作的索引(典型的循环),而 "B "寄存器被用来记录偏移量,帮助指定内存位置。所以,"A "和 "D "对于一些常见的算术函数来说可能更常见。

每个CPU指令都应该有一些文档,用汇编编程的人都会用到。这些文档应该指定每个指令使用哪些寄存器。(所以选择使用哪些寄存器通常是由CPU的设计者指定的,而不是汇编语言的程序员。虽然,可以有一定的灵活性。)

现在,回到上面例子中的 "40":那是一系列的位,通常被称为 "flags寄存器"。flags寄存器中的每个位都有一个名字。例如,有一个 "溢出 "位,如果结果大于可以存储一个字节的空间,CPU可能会设置 "溢出 "位。("溢出 "位通常可能被称为 "OF "的缩写。那是一个大写的O,不是0)。软件可以检查这个标志的值,并注意到 "问题"。处理这个位的工作通常是由更高级别的语言隐蔽地处理的,所以初学的程序员通常不会学习如何与CPU标志进行交互。然而,汇编程序员通常会以一种与其他变量非常相似的方式访问这些标志。一条ADD指令可能会在A寄存器和D寄存器中存储16位结果,而另一条指令可能只在A寄存器中存储8个低位,忽略D寄存器,并指定溢出位。然后,以后(在将A寄存器的结果存储到主RAM中后),你可以使用另一条ADD指令,只将8个高位存储在寄存器中(可能是A寄存器)。

(通常也有一个 "underflow "标志,以防止你减去太多的东西而不能满足所需的结果。)

只是想告诉你事情有多复杂: Intel 4004 是一个4位的CPU Intel 8008 是一个8位的CPU。英特尔8008是一个8位的CPU,它有8位寄存器,名为A、B、C和D。它有16位寄存器,命名为 AX、BX、CX和DX。 英特尔80386是32位CPU。它有32位寄存器,名为EAX、EBX、ECX和EDX。 英特尔x64芯片的CPU有64位寄存器,名为RAX、RBX、RCX和RDX。x64芯片可以运行16位代码(在某些工作模式下),并可以解释16位指令。这样做的时候,构成AX寄存器的位数是构成EAX寄存器的一半,而构成RAX寄存器的位数是构成RAX寄存器的一半。因此,无论何时改变AX的值,你也是在改变EAX和RAX,因为AX使用的那些位是RAX使用的位的一部分。如果改变EAX的值是65,536的倍数,那么低16位是不变的,所以AX不会改变。如果改变EAX的值不是65,536的倍数,那么AX也会受到影响)。

现在,如果你使用的是8位的CPU,当你写到内存时,你可能会发现一些限制,就是可以引用8位的地址,而不是4位或16位的地址。具体的情况会根据CPU的不同而有所不同,但如果你有这样的限制,那么CPU可能是在处理8位的字,这也是为什么CPU最常被称为 "8位CPU "的原因。

Advertisement