当我在另一个嵌套函数中调用一个trampoline 嵌套函数时,trampoline 嵌套函数无法访问trampoline 变量,在本例中为浮点数r
。
typedef void (*callback)();
callback Wrapper(float r) {
auto void foo();
void foo() {
// do something with r.
}
return &foo;
}
int main(void)
{
callback c = Wrapper(0.1);
auto void foo2();
void foo2() {
c(); // doesn't work unless i don't use r in foo (Segmentation fault (core dumped))
}
foo2();
c(); // works fine.
return 0;
}
答案 0 :(得分:3)
来自gcc documentation nested functions:
<块引用>如果你在包含函数退出后试图通过它的地址调用嵌套函数,一切都会崩溃。
函数void foo
在函数Wrapper
中定义,函数foo
的地址从Wrapper
返回。然后在函数 Wrapper
退出后调用该函数。正如文档所述,您的代码使“一切都崩溃了”。
将嵌套函数视为分配在堆栈上的变量。当函数返回时,嵌套函数停止存在。
<块引用>trampoline 嵌套函数无法访问trampoline 变量,在本例中为float r。
变量 r
仅在 Wrapper
函数内具有作用域。一旦 Wrapper
退出,变量 r
将停止存在。
auto void foo();
auto void foo2();
这很奇怪。没必要这么写。只需编写函数 - 无论如何,默认情况下它就像 auto
。
答案 1 :(得分:1)
一旦 c()
完成,您就不能使用 Wrapper()
,因为它超出了范围。把它想象成这个函数只在 Wrapper()
被执行时才存在(即使你知道它的代码还在某处,你不能因为下面解释的原因执行它,如果它不是从函数内部包含它)您在 Wrapper()
的开头调用 main()
,并且 Wrapper()
返回一个指向 Wrapper()
本地函数的指针。好吧,那个指针是一个假指针,因为一旦程序从 Wrapper
返回,这个函数就不再存在了。这就像返回一个指向局部变量的指针。
我应该说未定义行为,但是当我们谈论 GCC 扩展时,该术语也超出了范围,那么我能说什么呢? (正如我从 KamilCuk 的另一个答案中看到的那样,GNU 使用术语all hell break down,这对我来说听起来很完美)
嵌套函数的实现意味着使用显示(指向所有嵌套函数中最接近的活动调用记录的指针数组,这是在其他语言中完成的,如 Pascal、Ada 或 Modula-2)来访问外部函数中的范围标识符,就像您一样,当您从 float r
访问 c()
时,但稍后,当 Wrapper
没有被执行时,{{ 中不存在局部变量的显示1}} 并且对 Wrapper()
的调用是错误的,因为对值 c()
的访问很久以前就没有了。
出于所有目的,您尝试调用 1.0
超出范围(c()
之外)的技巧是非法的,我不知道为什么您可以要求这样做,但是如果你以为你可以维护一个本地资源(比如Wrapper()
中的参数r
,在调用使用它的函数后返回)
我建议您通过查看嵌套函数的汇编代码(您可以无限嵌套,并且在每一级嵌套都添加一个指向向量的指针)在标准 C 中没有显示,因为所有函数都在顶层定义。