人们谈论堆栈和堆之间的区别。但我很好奇,如果CPU不支持堆栈和堆结构,那么C语言是否可以在没有堆栈和堆的情况下正常运行?
人们谈论堆栈和堆之间的区别。但我很好奇,如果CPU不支持堆栈和堆结构,那么C语言是否可以在没有堆栈和堆的情况下正常运行?
然而,使用其标准调用和返回技术(SCRT),它可以相当不错地处理子例程和堆栈(“不错”这个词的定义因人而异)。有关此美丽之物(或者说是丑陋的怪兽,取决于您的观点)的工作原理以及其他一些不寻常的架构细节,请参见此处。
IBM Z(又称System z、zSeries或者像本周他们所称呼的任何名称)实际上拥有一个堆(某种程度上,您可以从操作系统中分配内存),但没有堆栈。它实际上通过使用此堆内存以及某些寄存器(类似于上面链接中引用的RCA芯片)来实现一个链接列表堆栈,这意味着函数前奏使用STORAGE OBTAIN
分配本地函数内存,而函数结尾使用STORAGE RELEASE
释放它。
不用说,这会为每个函数的前奏和结尾增加不少额外代码。
根据其他答案所述,C11标准并不要求使用堆栈或堆(参见n1570)。但是,在实践中,两者都是有用的。
关于调用堆栈,它非常常见,但可以“避免”:
一些优化编译器可能足够聪明(尤其是在整个程序优化或链接时优化的情况下),可以检测到整个程序不需要任何调用栈的情况(一个简单的例子是没有函数指针和递归的整个程序:在这种情况下,每个“调用帧”都可以在编译时静态分配)。许多优化编译器甚至对未标记为inline
的函数进行内联调用(有效地消除了这些调用的调用栈需求)。
许多现代处理器(x86或x86-64、AVR、SPARC、ColdFire即mc68K...)都有一个硬件调用栈(例如某些 "堆栈指针" 寄存器,已知于函数调用)。在那些没有这样的硬件堆栈指针的处理器上(例如IBM Z系列大型机、PowerPC、MIPS、RISC-V,或者也许是ARM),调用约定(或ABI)可能会传统地将一些寄存器指定为堆栈指针的角色。顺便说一下,C甚至可以在随机访问机器上理论上实现(这些机器没有任何寄存器或堆栈指针)。
人们可以想象一个编译器使用延续传递风格来避免调用栈(有效地在堆中或者某些堆中“分配”一些“调用帧”,也许需要一些垃圾收集器的帮助)。Appel的旧书Compiling with Continuations详细解释了这个想法。我不能列出任何使用此方法的C编译器,但标准允许这种方法。如果您编写了从C到SML(或某些Lisp)的编译器,您就可以拥有这样的编译器。
malloc
函数可能会失败,这仍然符合标准。我认为这样的 malloc
是无用的,但可能是最快的。此外,C 标准允许独立实现不包含任何 malloc
。
'SP'
寄存器开始,它们已经深入编程中。如果没有“堆栈”(或其概念),该寄存器可能会有不同的缩写。要进行良好的历史回顾,请参见堆栈概念在处理器寄存器中的普遍性。 - David C. Rankin