alloca 是完全可以替换的吗?

Posted

技术标签:

【中文标题】alloca 是完全可以替换的吗?【英文标题】:Is alloca completely replaceable? 【发布时间】:2011-03-30 03:56:35 【问题描述】:

我读过很多地方,alloca 已过时,不应使用,而应使用可变长度数组。

我的问题是:alloca 完全可以被可变长度数组替换吗?

在我的特定实例中,我有一些看起来像这样的东西:

typedef struct  
  int *value; 
  size_t size; 
   some_type;

void SomeExternalFunction(some_type);

...

void foo()
  //What I thought to do
  some_type bar;
  bar.value=alloca(sizeof(int)*10);
  SomeExternalFunction(bar);

  //what should be done without alloca
  some_type fizz;
  int tmp[10];
  fizz.value=tmp;
  SoemExternalFunction(fizz);

我是否遗漏了什么,或者这是对 alloca 的实际使用?还假设对于这个例子,出于某种原因,我希望在堆栈上分配值

【问题讨论】:

这实际上不是一个可变长度数组...因为您指定了一个恒定长度。而且...即使它 可变长度,我并没有真正看到 alloca 在这里给你买了什么,除了让代码的意图稍微更加模糊之外。 (显然,如果您使用的编译器不支持可变长度数组,则无论如何您都无法在两者之间进行选择) 另请参阅:***.com/questions/3452434/…(根据标题可能是重复的,但我觉得你真的想问别的……但我不知道是什么) 【参考方案1】:

VLA 和 alloca 之间有一个重要区别:内存 alloca() 返回是有效的只要当前函数持续存在。 VLA 占用的内存的生命周期只要 VLA 的标识符仍在范围内就有效。例如,您可以在循环中分配内存并使用循环外部的内存,VLA 将消失,因为当循环终止时标识符超出范围。这意味着,您可以使用 alloca() 和足够的堆栈空间来做到这一点:

typedef struct node  int data; struct node *next; ;
void fun()

 struct node *n=0;
 int d;
 /* Now we are building a single-linked list on the stack! */
 while(d=get_something()) 
  struct node *x=alloca(sizeof(*x));
  x->next=n; 
  x->data=d;
  n=x;
 
 do_something_with(n);
 // and the whole thing is deleted here..

VLA 无法做到这一点。

【讨论】:

FWIW:这对于In which cases is alloca() useful? 和What’s the difference between alloca(n) and char x[n]? 来说都是一个很好的答案 这是关于差异的一个很好的答案,但您可能还想注意 alloca 的行为本质上是实现定义的,因为它没有在任何(当前)标准中指定。 顺便说一下,一种方法可以对 VLA 做同样的事情:使函数递归并在最深层调用 do_something_with(n)。 :-) 实际上,我对此有一个实际用途,但我还没有实现:/lib/ld.so 的轻量级实现,它在堆栈上执行动态链接以避免将malloc 开销带入不支持的小型程序中用它。最后,当且仅当libdl 未被链接时,它才会展开并丢弃所有动态链接数据;否则它将从最深的递归级别调用_start @R:我记得在某处读到过 were/are alloca 在当前大括号部分离开时释放。因此,查看手册可能是个好主意。 @R:Chicken Scheme 使用类似的技术来执行其分配:程序被编译成一组函数,这些函数调用带有尾调用的延续,这意味着所有分配都可能发生在堆栈上。当堆栈已满时,垃圾收集器会将活动对象移动到堆中,并通过执行“返回”来回退堆栈。【参考方案2】:

alloca 完全可以被mallocfree 替换。这是一个多一点的工作,但除非你非常小心,否则它是必不可少的。几乎所有使用 alloca 或 C99 vla 的代码都容易受到堆栈溢出攻击,并且在许多实现中,它们可能导致特权提升。没有可移植的方法来知道堆栈有多大或剩余多少堆栈空间(或者编译器的内部使用或进一步的函数调用可能需要超出请求大小的多少开销),所以你可以做的唯一合理的事情是使 vla's/alloca 安全是对您支持的数据大小(例如几 kb)施加极小的人为限制。此时,您还不如只使用普通的非可变长度自动对象...

【讨论】:

堆正在完全取代堆栈。没有。 在实时上下文中,必须只使用堆栈并避免堆内存(malloc/free/new),因为当系统需要将页面交换到磁盘时,分配可能会使线程暂停几秒钟。 @diemo:这些说法都不是真的。使用堆栈可能导致分页(如果堆栈指针跨入新页面并且该页面尚未被实例化或被换出或丢弃)并且不需要使用分配的(“堆”)内存导致交换(例如,如果没有磁盘)。

以上是关于alloca 是完全可以替换的吗?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 是不是可以无缝替换为 MariaDB,或者在这种情况下有啥需要改变的吗?

已知道Excel文件的密码,用JAVA如何读取?我原来用的是jxcell 但是这个包是收费的 有啥可以替换这个的吗

用 Blade 组件替换 Vue 组件,是不是完全有可能?

我可以使用 Nuxt Apollo 本地状态来完全替换 Vuex 吗?

如何在 Git 中完全用远程分支替换本地分支?

六大设计原则LSP里氏替换原则