那是 C++ 或 C#,而不是 C。
如果您使用 MARS 或 SPIM,则有一个针对 sbrk 的系统调用,您可以使用它来实现堆分配器。 http://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html。如果你不关心以后释放内存,直接使用它:syscall 和$v0=9 分配$a0 更多字节的堆空间,并返回$v0 中的指针。
但通常你可以只保留一些堆栈空间,如果可以在函数结束时释放它作为拆除该函数堆栈框架的一部分。
在 C++ 以外的一些高级语言中,没有与 alloca 或 int array[10] 等效的方法来创建一个本地数组,其存储范围仅限于函数,因此即使私有临时数组也必须使用与完整数组相同的语法-关于长寿命对象的动态分配。
此类语言的编译器使用escape analysis 来确定对该存储的引用是否可以在函数结束后继续存在。如果没有,可以在堆栈上分配存储。 (但如果它确实逃逸了,它必须在堆上分配,例如使用malloc 或mmap。)
手动“编译”为 asm 时,您应该自己进行转义分析。如果您不返回指向存储的指针,并且您不将其地址传递给任何持有它的函数,那么它只是您可以并且应该为其保留堆栈空间的暂存空间,而不是调用分配和释放系统调用。
在 MIPS 上,这是 gcc5.4 对简单函数 (source+asm on Godbolt) 所做的:
void foo(void) {
volatile int scratch[10]; // volatile so it can't optimize away
scratch[1] = 0;
}
# gcc -O3 -fno-delayed-branch
foo():
addiu $sp,$sp,-48 # allocate space
sw $0,12($sp) # store into it from the zero-register
addiu $sp,$sp,48 # restore stack pointer
j $31 # return
nop # branch-delay slot filled with a NOP
所以 gcc 决定从 $sp + 8 开始从头开始,所以第一个 4 字节元素之后的一个 4 字节元素位于 $sp + 12。