【问题标题】:C calling nested function inside another nested functionC在另一个嵌套函数中调用嵌套函数
【发布时间】:2021-02-16 08:49:44
【问题描述】:

当我在另一个嵌套函数中调用蹦床嵌套函数时,蹦床嵌套函数无法访问蹦床变量,在本例中为浮点数,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;
}

【问题讨论】:

  • 嵌套函数不是标准的 C 特性。所以最好不要使用它们。
  • 取决于上下文。如果出于某种原因承诺使用非标准的东西。例如。团队所有的人都使用 gcc 工具链,那么使用 gcc 扩展呢(嵌套函数实际上就是这样的特性)?。
  • 嗯,这大致就像访问其范围之外的局部变量...文档说 如果您在包含函数退出后尝试通过其地址调用嵌套函数,所有地狱都会崩溃。
  • 也许你应该考虑切换到 C++17。它是一种非常复杂的语言,但它有 lambda expressionsstd::function 并且非常小心,您可以用 C++ 编写一个可从 C 代码调用的库(例如 libgccjit...)
  • 另一种方法是在运行时生成机器代码(可能生成 C 然后将其编译为插件)。发送电子邮件至 以获取详细信息和示例。在 Linux 上以 manydl.c 为例

标签: c gcc


【解决方案1】:

来自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

【讨论】:

    【解决方案2】:

    一旦Wrapper() 完成,您就不能使用c(),因为它超出了范围。可以将其想象为该函数仅在执行 Wrapper() 时才存在(即使您知道它的代码仍在某处,由于下面解释的原因,如果它不是来自包含的函数内部,则无法执行它它)您在main() 的开头调用Wrapper()Wrapper() 返回一个指向Wrapper() 本地函数的指针。好吧,那个指针是一个假指针,因为一旦程序从Wrapper 返回,该函数就不再存在了。这就像返回一个指向局部变量的指针。

    我应该说未定义的行为,但是当我们谈论 GCC 扩展时,该术语也超出了范围,那我能说什么呢? (正如我从 KamilCuk 的另一个答案中看到的那样,GNU 使用了 all hell break away 这个词,这对我来说听起来很完美)

    嵌套函数的实现意味着使用显示(指向所有嵌套函数的最近活动调用记录的指针数组,这是在其他语言中完成的,如 Pascal、Ada 或 Modula-2)来访问外部函数中的范围标识符,就像你做的那样,当你从 c() 访问 float r 时,但后来,当 Wrapper 没有被执行时,Wrapper() 中不存在局部变量的显示和对 @ 的调用987654333@ 是错误的,因为对值 1.0 的访问权限早已消失。

    出于所有目的,您尝试在范围之外(Wrapper() 之外)调用 c() 的技巧是非法的,我不知道您为什么需要这样做,但如果您认为可以,那您就错了维护一个本地资源(如Wrapper中的参数r,在调用使用它的函数后返回)

    我建议你看看嵌套函数指针数组以及编译器如何通过显示访问外部函数上的变量,通过查看嵌套函数的汇编代码(你可以无限嵌套,并且在每一层嵌套,你都添加一个指向向量的指针)在标准 C 中没有显示,因为所有函数都在顶层定义。

    【讨论】: