我觉得这可能是一个奇怪/愚蠢的问题,但这里有......
在问题Is NULL in C required/defined to be zero?中,已确定NULL
指针指向无法寻址的内存位置,NULL
为0
。
现在,据说32位处理器可以处理2^32
个内存位置。
2^32
只是可以使用32
位表示的不同数字的数量。这些数字中有0
。但是,因为0
,即NULL
,应该指向任何东西,我们不应该说32位处理器只能处理2^32 - 1
个内存位置(因为{{ 1}}不应该是有效的地址)?
答案 0 :(得分:9)
如果32位处理器可以处理2 ^ 32个内存位置,那只是意味着该架构上的C指针可以引用2 ^ 32 - 1个位置加上 NULL 。
答案 1 :(得分:8)
NULL指针指向无法寻址的内存位置
事实并非如此。从您链接的问题中接受的答案:
请注意,由于如何制定空指针的规则,用于分配/比较空指针的值保证为零,但实际存储在指针内的位模式可以是任何其他东西
我所知道的大多数平台实际上通过将地址空间的前几页标记为无效来处理此问题。这并不意味着处理器无法解决这些问题;它只是一种方便的方法,使低值成为无效指针。例如,几个Windows API使用它来区分资源ID和指向实际数据的指针;低于某个值的所有内容(如果我没记错的话,为65k)不是有效指针,而是有效的资源ID。
最后,仅仅因为C说某事并不意味着CPU需要以这种方式受到限制。当然,C表示访问null模式是未定义的 - 但是没有理由在汇编中进行编写需要受到这些限制。真正的机器通常可以做得比C标准所说的要多得多。虚拟内存,SIMD指令和硬件IO是一些简单的例子。
答案 2 :(得分:0)
这取决于操作系统。它与virtual memory和address spaces
相关在实践中(至少在Linux x86 32位上),地址是字节“数字”s,但大多数是4字节字,因此通常是4的倍数。
更重要的是,从Linux应用程序中看到 ,只有最多 4Gbytes中的3G字节是可见的。未映射整个千兆字节的地址空间(包括空指针附近的第一页和最后一页)。在实践中,这个过程看起来更少。请参阅其/proc/self/maps
伪文件(例如,运行cat /proc/self/maps
以查看Linux上cat
命令的地址映射。
答案 3 :(得分:0)
首先,让我们注意线性地址(AKA指针的值)和物理地址之间的区别。虽然线性地址空间实际上是32位(AKA 2 ^ 32个不同的字节),但到存储器芯片的物理地址并不相同。线性地址空间的部分(“页面”)可能会映射到物理内存,或页面文件,或任意文件,或标记为不可访问且不受任何内容支持。第零页恰好是后者。映射机制在CPU级别实现,并由OS维护。
也就是说,零地址是不可寻址的内存只是自第一个Unices以来每个保护模式OS强制执行的C约定。在MS-DOS时代的实模式歌剧系统中,null far指针(0000:0000)是完全可寻址的;但是,在那里写文件会破坏系统数据结构并带来麻烦。空指针(DS:0000)也可以完全访问,但运行时库通常会在零周围保留一些空间,以防止意外的空指针解除引用。此外,在实模式下(如在DOS中),地址空间不是32位的扁平空间,实际上是20位。