虚函数是否不太可能导致堆栈溢出?

时间:2017-06-01 22:27:23

标签: c++ memory embedded virtual-functions

在一次采访中,我被问到函数参数是否位于堆栈或堆中。我很确定这是作为一个例子来说明由于嵌入式内存规模的堆栈溢出风险如何避免递归函数。然而,这似乎是一个棘手的问题,因为我一直在审查虚拟功能,允许dynamic dispatch

SO周围搜索后,似乎普通旧常规函数参数的内存位置依赖于实现。

其他答案对于虚函数几乎都说同样的事情 - 不保证虚拟函数参数在内存中的实现方式。

所以我想明白:

  1. 运行时函数实现的方式和位置(堆栈?堆?smattering)?

  2. 在不知道ABI所说的内容的情况下,知道/找到这种信息的好地方或者有更好的地方可以查看吗?除了规范之外,是否有任何实验数据可以让我们在实践中“看到”内存的平均工作方式?

  3. 另外,先发帖你好!

4 个答案:

答案 0 :(得分:1)

您可以非虚拟地调用virtual功能。因此,它不是函数的定义,而是决定虚拟的调用类型。因此,实际上不可能有不同的约定。

答案 1 :(得分:0)

参数和返回值的位置是调用约定的保留,有许多调用约定,它们都有细微差别。 在64位x86计算中,只有2种调用约定值得考虑微软和SystemV。 两种调用约定都旨在尽可能多地传递寄存器。我的头顶是4个整数参数和4个浮点参数。有一些特殊情况,但总的来说,除此之外的任何东西都会被推到堆栈。

答案 2 :(得分:0)

参数/返回值的传递方式和位置由函数的调用约定定义,virtual对此没有任何影响。一些调用约定仅使用堆栈,而其他约定使用堆栈和CPU寄存器的混合。但绝不是堆。

virtual唯一能做的就是决定如何确定函数地址,以及在隐藏的this参数中传递什么值。但参数值(包括this)和返回值仅基于调用约定传递。

在32位,实现标准化的两个调用约定是__cdecl__stdcall。其他调用约定是实现定义的,如__fastcall__thiscall

在64位上,ABI定义了一个所有实现必须遵循的单一调用约定。忽略32位调用约定。

答案 3 :(得分:0)

“调用函数”的整个想法本质上与堆栈相关联。调用约定可以将一些参数移动到寄存器,间接传递参数(通过指针或引用)可以减少传递的实际数据量,但仍然必须在堆栈上推送返回地址。

没有堆栈影响的合法方式是内联函数,人们可能认为这本身并不是一个“函数调用”,并且现在越来越难以保证 - 也就是说,决定取决于编译器。
可以内联尾递归,将其转换为无限循环,从而不会永远耗尽堆栈。

最后,virtual连接到任何一个的唯一方法是动态链接的调用更难以内联 - 它们需要首先进行虚拟化,这仍然不是不可能的。

总体结论似乎是“如果有任何联系,那么它支持非virtual函数”。