我的应用程序有一个main函数,例如,我分配配置文件的路径等。目前我使用malloc它们,但它们永远不会被释放,并且在应用程序的整个生命周期中始终可供使用。我什至从未释放它们,因为当应用程序终止时操作系统已经自动回收分配的内存。此时,是否有任何理由不使用allocamalloc 来代替,因为程序在main返回时结束,并且alloca只有在释放分配的函数后才会删除内存。因此,根据这个逻辑,在主函数中分配的内存alloca只有在程序结束时才会被释放,这是所期望的。这些陈述是否正确,是否有任何理由不使用alloca(alloca 是不好的做法,所以当我说 alloca 意味着 alloca或在 中创建 VLA main)main作为“全局 VLA”之类的对象,该对象将持续到程序终止?
在得知 VLA(可变长度数组)与 C++ 不兼容后,我第一次开始研究这个兔子洞。这是因为可变长度的数组在编译时不会有一个常量的大小,而 C++ 编译器需要它来计算程序将要分配的堆栈帧的大小运行。我知道这种在编译时知道这样的事情的愿望就是禁止 VLA 数组的原因(以及其他原因)。
但是,为什么需要在编译时知道这样的事情(要分配的堆栈帧的大小)?为什么不能确定堆栈所需的所有内存,然后在运行时分配?我听说它解释说,在编译时确定堆栈帧的大小对于避免堆栈溢出异常很有用,因为您提前确切地知道给定函数调用需要多少内存。如果我们允许堆栈上有一个 VLA,其大小由运行时用户输入确定,他们可以输入一个巨大的数字,例如 100000000000,然后我们会得到堆栈溢出异常。禁止使用 VLA 可以让我们避免做类似的事情(或者至少我是这么理解的)。
这就是向我解释的,但我仍然不明白为什么这意味着一切都必须在编译时确定。例如,alloca可以通过简单地移动堆栈指针来在运行时在堆栈上进行分配。为什么不能在运行时为函数中的每个新局部变量在内部完成此操作,以便我们可以拥有 VLA 而不是立即分配整个堆栈帧?我觉得答案应该是“很明显,所以你最终不会尝试分配比你拥有的更多的内存并导致堆栈溢出异常!”,但无论你采用什么技术,这不是一个风险吗?我可以尝试在运行时在堆上声明我的可变长度数组,但是如果我尝试分配比可用内存更多的内存怎么办?在这种情况下,我遇到了同样的问题,由于用户输入而占用了超出我所能承受的内存,并且在编译时计算程序的内存使用量无法拯救我。
那么,在编译时这样做仅仅是为了提高效率吗?如果是的话,是什么让它更有效率?难道我们只是提前计算需要为函数调用分配多少内存,而不是在运行时计算,从而在每次调用函数时节省几微秒的时间?
c++ stack-overflow alloca compile-time variable-length-array
这本质上是我的问题.在函数的生命周期中,我生成一些整数,然后在算法中使用整数数组,该算法也是同一函数的一部分.整数数组只能在函数中使用,因此将数组存储在堆栈中自然是有意义的.
问题是我不知道数组的大小,直到我完成生成所有整数.
我知道如何在堆栈上分配固定大小和可变大小的数组.但是,我不知道如何在堆栈上生成数组,这似乎是解决我的问题的最佳方法.我相当确定这可以在汇编中完成,你只需增加堆栈指针并为每个生成的int存储一个int,因此int数组将位于堆栈帧的末尾.这可能在C中做到了吗?
文档在这里_alloca()说:
_alloca 例程返回一个指向已分配空间的 void 指针,保证该空间能够适当对齐以存储任何类型的对象。
然而,这里说:
_alloca 需要 16 字节对齐,并且还需要使用帧指针。
因此,似乎在第一个参考文献中,他们忘记了 32 字节对齐的 AVX/AVX2 类型,例如__m256d.
另一件让我困惑的事情是,第一页说_alloca()已弃用,而它建议使用可以从堆而不是堆栈分配内存的函数(这在我的多线程应用程序中是不可接受的)。
那么有人可以指出我是否有一些现代的(也许是新的 C/C++ 标准?)方法来对齐堆栈内存分配?
说明 1:请不要提供需要数组大小为编译时常量的解决方案。我的函数根据运行时参数值分配可变数量的数组项。
我听说有一个版本sprintf(),可能是一个GNU/gcc扩展,它可以分配自己的缓冲区,我必须free()或者可能使用堆栈就像alloca().
这两种方法都适合我.谁能告诉我我在想什么功能?
C一直是个谜!
我正在实现一个工作组线程执行模型,我试图使用alloca作为更快的内存分配选项.尝试通过使用alloca存储在堆栈中的函数指针执行代码时,我有一个奇怪的分段错误.
这是一个牙齿挑选代码,导致类似的分段错误:
#include <stdlib.h>
#include <stdio.h>
typedef void* (*foo)(void*);
typedef struct task
{
    foo f;
} task;
void *blah(void* v)
{
    printf("addr:%p\n", &v);
    return v;
}
int main()
{
    void *queue[10]; 
    task *t = (task*) alloca (sizeof(task));
    // No null check, excuse me!
    t->f = blah;
    queue[0] = (void*)t;
    char string[10] = "Bingo!";
    char *c = &string[0];
    task *tnew = (task*)&queue[0];
    tnew->f((void*)c);
    return 0; 
}
Run Code Online (Sandbox Code Playgroud)
当我执行上面的代码时,我在tnew-> f()行得到了一个分段错误.GDB回溯对我没什么帮助.
请解释上面代码中的错误..我是第一次使用alloca.
非常感谢你!
此代码是否返回对堆栈上分配的变量的无效引用?或者是什么:
void *f(size_t sz) {
    return alloca(sz);
}
Run Code Online (Sandbox Code Playgroud)
或者这是一个由alloca实现/编译器支持处理的特殊情况f(alloca(size), alloca(size))?
一些编译器支持C++扩展,从而可以在堆栈上动态分配内存.例如,g++支持alloca()以及VLA.所有这些扩展都伴随着警告,即动态分配的内存在调用函数范围的末尾被"释放".(编辑:为了澄清,我使用'deallocated'周围的引号,因为实际发生的是编译器递减/递增堆栈指针,因此为什么alloca()需要编译器支持.)这意味着alloca()在类的构造函数中使用分配的内存被释放一旦构造函数返回.
在构造函数经历一些非常重要的步骤来确定要分配多少内存的类中,这种限制变得难以处理.该类的用户必须在构造类的函数中分配内存,暴露一些可能不应该暴露的内部.此外,将解决方法放在我的代码中以便能够使用alloca()或使用VLA通常是不方便的.
你能想出一些方法来绕过这个限制,以便我可以使用alloca(),VLA或其他语言扩展,以便内存可以在类中分配并具有类范围吗?
让我们从一个简单的堆栈分配示例开始:
void f() {
    int a, b;
    ...
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话。a那么和的地址b与栈基址(即寄存器 )有固定的偏移量ebp。如果我们以后需要它们,这就是编译器找到它们的方式。
但请考虑以下代码。
void f(int n) {
    int a;
    alloca(n);
    int b;
    ...
}
Run Code Online (Sandbox Code Playgroud)
如果编译器不做任何优化,堆栈将为a->n->b. 现在 的偏移量b取决于n。那么编译器做了什么?
模仿alloca() 在内存级别如何工作?。我尝试了以下代码:
#include <stdio.h>
#include <alloca.h>
void foo(int n)
{
    int a;
    int *b = alloca(n * sizeof(int));
    int c;
    printf("&a=%p, b=%p, &c=%p\n", (void *)&a, (void *)b, (void *)&c);
}
int main()
{
    foo(5);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是&a=0x7fffbab59d68, b=0x7fffbab59d30, …