如果使用alloca在内联函数中的堆栈上分配变量,那么在内联函数返回后,其引用是否有效

If a variable is allocated on the stack in an inline function using alloca, is its reference valid after the inline function returns?

本文关键字:函数 返回 是否 有效 引用 alloca 分配 如果 堆栈 变量      更新时间:2023-10-16

我知道编译器可能,而不是应该inline函数展开到调用函数中,以避免与调用离线函数相关的开销。然而,我也知道inline函数与离线函数的链接方式不同,所以我不能指望它们以完全相同的方式进行操作。

当我实际使用C++时,我正在使用一个api开发一个程序,在这个程序中,可以方便地使用看起来像的C宏

#define func_alloca(ptr) do { *ptr = alloca(size); memset(*ptr, 0, size); }

为了避免在不同的函数中多次重复代码,我可以对一系列alloca调用进行功能化。我的问题是,(特别是在gcc中,由于alloca是实现定义的,)我可以在inline函数内部使用alloca初始化堆栈上的变量,并指望它们在外部工作吗?下面是我想做的一个例子:

inline void uses_alloca(type*& ptr){
    // do stuff
    func_alloca(ptr);
}
void calls_inline(){
    type *local_ptr;
    uses_alloca(local_ptr);
    // is local_ptr valid?
}

如果它确实有效,它是否总是有效?与中一样,不仅当编译器选择将inline函数展开到调用函数中时?

编辑:

我的猜测是,这可能实际上会起作用,因为alloca调用在宏中包含的do{}本地作用域之外已经有效,而且,如果我理解正确的话,函数在C++中的作用域级别实际上与do{}块不同。我的问题仍然是:alloca在gcc中应该是这样工作的吗?这是已定义的行为吗?

声明函数inline不会将所包含变量的范围扩展到将其扩展到的范围。因此,无论alloca分配什么,都不能保证在调用函数uses_alloca的上下文中都是有效的。如果您使用func_alloca,您就可以了,因为宏文本实际上是就地展开的。然而,alloca本身的使用通常被认为是一种糟糕的做法。

如果使用GCC,预期的行为是其中包含alloca的函数不会自动内联。来自tree-inline:

  /* Refuse to inline alloca call unless user explicitly forced so as
 this may change program's memory overhead drastically when the
 function using alloca is called in loop.  In GCC present in
 SPEC2000 inlining into schedule_block cause it to require 2GB of
 RAM instead of 256MB.  Don't do so for alloca calls emitted for
 VLA objects as those can't cause unbounded growth (they're always
 wrapped inside stack_save/stack_restore regions.  */

这当然没有考虑到:

  • Bugs
  • 编译器内联函数,因为它不是完美的
  • 优化开关、属性
  • 运气不好

内联上的GCC手册页警告说,内联函数不适合alloca,为什么alloca()的使用不被认为是好的做法?还有一些恐怖故事。

本质上,如果你担心内联可能会影响代码的语义,就不要依赖它