C是否需要堆栈和堆才能运行?

Does C need a stack and a heap in order to run?

人们谈论堆栈和堆是什么以及它们之间的区别。但是我很好奇,如果CPU不支持栈和堆结构,那么C 运行可以不带栈和堆吗?

C 语言需要(正如 chqrlie 指出的那样)某种机制来实现自动存储并跟踪函数调用 return 点。实际上,这几乎总是一个堆栈。但它不需要堆。

只有在使用像 malloc 这样的库函数时,通常才需要堆;而不是 C 语言本身。堆实际上并没有什么神奇之处——你可以用纯 C 编写 mallocfree。它只是有一大块 static 内存,并且有一个分配 space 的算法] 来自方块。

你问“如果CPU不支持栈堆结构”怎么办? 好吧,栈和堆只是由内存和指针构成的。我不认为你会找到一个可以被视为“CPU”但不具备这种能力的处理器的例子。

不,不是。先覆盖堆,这个简单

不提供任何类型的堆的实现只需要在您尝试调用 malloc(或任何其他内存分配函数)时 return NULL。根据标准,这是完全可以接受的行为。


在堆栈方面,它也不需要提供。 ISO C11 提到单词 "stack" 正好零次。

实现 需要做的只是对标准中指定的所有内容进行正确的 "virtual machine"。当然,如果没有堆栈,这将非常困难,但这并非不可能。作为一个极端的例子,没有人说你不能简单地递归地内联每个函数调用。这将使用相当大量的代码和特定于函数的数据space,但这当然是可行的。

然而,这可能会说服我转向另一种架构,确实有一个堆栈(和堆,就此而言)。


话虽如此,即使一个体系结构既不提供堆也不提供堆栈,这两者都可以从基本内存 I/O 操作中构建出来。事实上,我十几岁时拥有的最早的电脑之一是 RCA 1802 CPU,它 没有 专用堆栈。它甚至没有 callret 指令。

然而,它可以使用其 SCRT(标准调用和 return 技术)很好地处理子例程和堆栈(对于单词 "well" 的某些定义)。请参阅 here 以了解有关这种美丽事物(或怪物,取决于您的观点)如何工作以及其他一些不寻常的架构的更多详细信息。


IBM Z(a.k.a。System z、zSeries,无论他们本周如何称呼它)实际上有一个堆(某种程度上,因为您可以从 OS ) 但没有堆栈。它实际上通过使用此堆内存和某些寄存器(类似于上面 link 中引用的 RCA 芯片)来实现 linked-list 堆栈,这意味着函数序言使用 STORAGE OBTAIN 并且 epilog 使用 STORAGE RELEASE.

发布它

不用说,在每个函数的序言和结尾中都添加了相当多的额外代码。

C11 标准(参见 n1570 不需要堆栈和堆,如其他答案所述。但是,在实践中,两者都是 有用的

关于call stack很常见,但也可能是"avoided":

  • 一些 optimizing compilers might be clever enough (notably with whole-program optimization, or link-time optimization) to detect the case where an entire program don't need any (a simple such case would be a whole program without function pointers and without recursion: in that case every "call frame" could be allocated statically at compile time). And many optimizing compilers are inlining 一些调用(有效地消除了对这些调用的调用堆栈的需要),即使对于未标记的函数 inline.

  • 许多当今的处理器(x86 or x86-64, AVR, SPARC, ColdFire i.e. mc68K...) have a hardware call stack (e.g. some "stack pointer" register, known to function calls). On those that don't have such a hardware stack pointer (e.g. IBM Z series mainframes, PowerPC, MIPS, RISC-V, or perhaps ARM), the calling convention (or the ABI) might conventionally dedicate some register to play the role of a stack pointer. BTW, C could even be implemented theoretically for random-access machines(没有任何寄存器或堆栈指针)。

  • 可以想象使用 continuation-passing style to avoid a call stack (effectively, "allocating" some "call frames" in the -or in some- heap, perhaps with the help of some garbage collector). Appel's old book Compiling with Continuations 的编译器会详细解释这个想法。我不能说出任何 C 编译器这样做,但标准允许这种方法。如果您将一些编译器从 C 编码为 SML(或某些 Lisp),您可以拥有这样的编译器。

关于 C 堆,malloc 函数总是会失败,但仍然符合标准。 I claim that such a malloc is useless,但可能是最快的。此外,C 标准允许独立实现根本没有任何 malloc

如果您寻找 C 几乎需要的功能,我会研究二进制表示。我倾向于相信为十进制计算机(如旧的 IBM 1620) or for ternary computers (like Setun) would be very impractical (but in principle it is possible, since you could "emulate" a binary computer on a ternary or decimal one; all are Turing-complete)实现 C11 编译器。但是,您只会在博物馆中找到这种老式(50 年代末、60 年代初)的计算机,并且在 C 发明之前它们就消失了。

顺便说一句,调用堆栈和堆存在于 ALGOL and Lisp (and IPL-V) 实现中,比 C 早了几十年