可以重新分配alloca()内存吗?

Phr*_*dge 6 c memory-management realloc alloca

所分配的内存malloc可以使用重新分配realloc。有类似的功能alloca吗?当您不希望在堆上分配内存时,并且您需要多次分配可变的堆栈内存(例如在需要动态内存但又不想动态存储的库函数中)时,重新分配堆栈内存可能很有用。在堆上分配,因为库的用户可能使用自定义堆分配策略。它看起来像这样:

int main(void) {
    float * some_mem = alloca(40 * sizeof(float));
    // do something with this memory...

    // now we need a different amount of memory, but some_mem still occupies a lot of the stack, so just reallocate it.

    // is something like this possible?
    some_mem = realloca(some_mem, 50 * sizeof(float));
}
Run Code Online (Sandbox Code Playgroud)

重要的是,这一切都发生在堆栈上。问:有没有办法重新分配动态堆栈内存?

Gil*_*il' 9

不:这与通常实现的堆栈不兼容。堆栈上的变量占用固定的地址范围。下一个变量紧随其后,因此没有增长空间。考虑这样的函数:

void f(int x) {
    int i;
    float *a = alloca(40 * sizeof(float));
    int k;
    …
}
Run Code Online (Sandbox Code Playgroud)

函数序号之后的堆栈如下所示:

----------------+-----+-----+-----+-------------------+-----+---------------------
...             | ret | x   | i   | a                 | k   | ...                 
----------------+-----+-----+-----+-------------------+-----+---------------------
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
previous frames                    f's frame                 free space at the top
Run Code Online (Sandbox Code Playgroud)

没有增长的空间a

我正在显示一个高度简化的示例:在现实世界中,变量最终存储在寄存器中,即使变量确实存在于堆栈中,也可以对其重新排序,等等。但是,只有一个变量可以是堆栈中最后一个有空间的变量成长。

因此,如果realloca存在,则只能将其应用于堆栈顶部的变量。(否则,它必须移动其上所有其他内容,但这将需要更新所有现有的指向这些对象的指针,通常这是不可能的。)这将是一个非常有限的机制,因此对此功能的支持必须很小的好处。支持它会产生巨大的成本,因为编译器通常可以自由地按所需顺序将它们放到堆栈上:此功能将需要一种新的机制,以使编译器知道一个特定的变量必须放在顶部。

某处的某些C实现可能具有realloca,但考虑到成本/收益比,这不太可能。

realloca如果alloca不使用堆栈分配策略,当然可以轻松实现。但是在堆栈上分配是重点alloca。如果需要可调整大小的对象,则需要带有堆接口的内存管理结构,这就是malloc目的。


实际上,库中有几种可能的动态内存管理方法。

最常见的方法是调用mallocreallocfree当你需要他们。那就是他们的目的。

在某些环境中,支持自定义分配器很有用。你可以给图书馆的用户指针传递到的替代实现的选择mallocreallocfree。当您要编写一个可移植的库,而该库需要由完全可移植的代码使用时,此功能很有用。但是,在大多数情况下,想要使用自定义分配器的用户可以通过链接自己的malloc朋友来实现。甚至很少有用。

如果您需要可以在没有动态分配的环境中工作的代码(例如对安全性要求很高的环境),那么您都不应使用alloca两者。allocamalloc它更糟糕,因为它会导致不可预知的堆栈使用情况,并可能导致根本无法检测到或仅由程序崩溃检测到的堆栈溢出。如果函数中需要可变(或大量)的临时内存,请让用户传递适当大小的缓冲区给您。

/** [documentation of the function] …
 * working_buffer must point to an array of floats of 3*n elements.
 */
void f(size_t n, float *working_buffer);
Run Code Online (Sandbox Code Playgroud)

更好的是,如果您有代码大小预算,请传递数组大小并进行验证。

/** [documentation of the function] …
 * working_buffer must point to an array of floats of 3*n elements.  
 */
int f(size_t n, float *working_buffer, size_t working_buffer_length)
{
    if (working_buffer_length < 3 * n) return -EINVAL;
    …
}
Run Code Online (Sandbox Code Playgroud)