C 在另一个嵌套函数中调用嵌套函数

时间:2021-02-16 08:49:44

标签: c gcc

当我在另一个嵌套函数中调用一个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;
}

2 个答案:

答案 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 中没有显示,因为所有函数都在顶层定义。

相关问题