为什么 NULL 不是有效的内存地址?

Jac*_*rby 4 c null

这可能听起来像一个愚蠢的问题,但因为在 C 中,NULL字面定义为

#define NULL 0
Run Code Online (Sandbox Code Playgroud)

为什么它不能是有效的内存地址?为什么我不能取消引用它,为什么任何数据都不可能位于内存地址 0 处?

我确信这个问题的答案是“前 n 个字节的内存总是由内核保留”,或者类似的东西,但我在互联网上找不到类似的东西。

我推理的另一部分是,这不是平台无关的吗?难道我不能发明一种新的架构,让进程可以访问内存地址 0 吗?

Bas*_*tch 5

取消引用NULL未定义的行为。任何事情都可能发生,而且大多数时候都会发生不好的事情。所以要害怕

一些旧的架构(VAX ...)允许您解除引用NULL

C11 标准规范(读为n1570)不要求NULL指针全部为零位(参见C FAQ Q5.17);它可能是其他东西,但它应该是一个永远无效的地址,因此在 C11 意义上无法通过成功的malloc或地址运算符(一元)获得。&但这样做更方便,并且在实践中大多数(但不是全部)C 实现都是这样做的。

IIRC,在 Linux 上,您可以mmap(2)(void*)0包含的页面MAP_FIXED,但这样做并不明智(例如,因为允许符合标准的优化编译器优化 的取消引用NULL)。

so(void*)0在实践中不是一个有效的地址(在具有一些 MMU 和运行足够好的操作系统的虚拟内存的常见处理器上!),因为可以方便地确定它是NULL,并且可以方便地确保取消引用它给出分段过错。但这不是 C 标准所要求的(并且在当今廉价的微控制器上是错误的)。

AC 实现必须提供某种方式来表示NULL指针(并保证它永远不是某个有效位置的地址)。这甚至可以通过约定来完成:例如提供完整的 2 32字节地址空间,但承诺永远不会使用地址 0(或您分配的任何地址NULL,也许是 42!)

NULL碰巧不可引用时,分段错误不会捕获微妙的错误(因此 C 程序更难调试)。

难道我不能发明一种新的架构,让进程可以访问内存地址 0 吗?

您可以,但您不想这样做(如果您关心提供任何符合标准的 C 实现)。您更喜欢将地址 0 设为NULL. 否则会使编写 C 编译器(和标准 C 库)变得更加困难。并使该地址无效,以至于在解除引用时出现分段错误,从而使调试(以及用户用 C 语言编码的生活)变得更容易。

如果您梦想着奇怪的架构,请阅读有关Lisp 机器(以及Rekursiviapx 432)的内容,并参阅Liam Proven 在 FOSDEM2018 上发表的电路较少旅行的演讲。这确实很有启发性,而且是一次很好的演讲。

  • 0是绝对有效的内存地址。它是可寻址存储器的第一个元素。然而,许多实现_定义_ 0 对于应用程序的所有实际使用来说是无效的内存地址,并且通常让内存管理硬件触发异常以向应用程序/开发人员发出信号,表明存在问题。 (2认同)