为什么32位和64位的地址长度不同?

4
当我在一台64位机器上运行此代码时:
‪#‎include ‬<stdio.h>
int main() 
{ 
    int a[10]; 
    printf("%p",&a);
    return 0;  
}

它输出:
0x7fffe9ebf984 (14 digits)

在一本教科书中我发现了这个问题:
我的计算机的存储地址是32位,在八个十六进制数字中表示。
我的问题是:
为什么32位和64位的地址有两个不同的长度?
在32位和64位中,8个数字和14个数字如何用于表示地址?

1
看起来像是12位数字,但可能会有前导零。处理器的内存地址大于32位,但根据处理器而定,可能小于64位。 - rcgldr
1
printf("%p",&a); 不需要打印所有前导的 0 数字,也不意味着存在一个连续的线性内存范围从 0 到 0x7fffFFFFFFFF。好奇的是,printf("%p",NULL); 会输出什么? - chux - Reinstate Monica
3个回答

9
那个内存地址只有12位数,而不是14位。每个数字是一个4位字。12*4=48,这是256太字节的地址空间。目前的CPU只使用全64位地址空间的低48位,因为这可以建造更便宜的晶体管(我们在不久的将来不会完全使用从64位中可用的内存)。当我们达到48位限制时,制造商可能会创建真正利用全64位地址空间的CPU,但现在还不必要。

1
那么在0x7fffe9ebf984中,实际地址是7fffe9ebf984吗? 这意味着我们不需要考虑0x吗? - Surya Teja Vemparala
1
0x只是告诉你这个数字是十六进制的,真正的地址应该是7fffe9ebf984。 - Fernando Garcia

7

首先,0x前缀表示接下来的是一个十六进制(基数为16)数字。十六进制系统扩展了十进制系统中的数字集合(0到9),使用a、b、c、d、e和f代表分别代表十进制数10、11、12、13、14和15。我们之所以更喜欢十六进制数而不是十进制数(至少在机器的字长是4的倍数时),是因为每个十六进制数字方便地对应于4位(二进制位)的一组。例如:

Hexadecimal: 3
Binary:      0 0 1 1
--------------------
Hexadecimal: F
Binary:      1 1 1 1

通常当我们提到机器是“32位”或“64位”时,我们指的是虚拟地址长度——即从用户模式进程的角度来看构成内存地址的位数。(这通常但不一定与字长相符。)
在x86-32机器上(例如旧版奔腾处理器),虚拟地址大小为32位。这意味着一个地址可以用八个十六进制数字来表示。例如,0x80000000代表2 GiB标记。虚拟地址为32位意味着任何给定进程只能直接引用4 GiB的内存(实际可用内存量甚至更小!)。

对于许多应用程序来说,例如大型内存数据库,4 GiB的虚拟内存空间太小,无法容纳数据集。这促使引入了64位机器,例如基于x86-64架构的机器。理论上,64位机器应该能够寻址16 EiB。但是,正如其他人所指出的那样,x86-64架构目前通过要求虚拟地址处于规范形式而将虚拟地址大小限制为48位。

顺便提一下,在规范地址空间的较低部分中的地址可以使用12个十六进制数字编写。通常,在打印时省略前导零。

如果有的话,从32位到64位计算机的完全转变不太可能很快发生。仍然有许多应用程序,特别是在嵌入式系统中,64位地址支持的内存量根本不需要;事实上,16位甚至8位微控制器仍然非常普遍。


1
你有32位和64位地址的原因与CPU架构有关。旧CPU使用32位,但使用32位地址限制了系统内存为4GB。这就是为什么要改为64位地址。系统可以支持更多的地址,因此可以支持更多的RAM。
你数字前面的“0x”只是告诉你它是十六进制的。所以实际上有12个数字,每个数字是4位(总共48位)。

1
吹毛求疵:32位地址长度限制了虚拟地址空间。物理内存可以更大,例如使用PAE - Martin Törnwall
2
注意:现今的嵌入式处理器(每年数十亿个)可能仅使用16位地址空间。 - chux - Reinstate Monica
在这两个观点上达成了一致。实际上,当我学习汇编语言时,人们正在讨论 16 位和 32 位之间的可移植性差异。 - It'sPete

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接