1

When I call a trampoline nested function inside another nested function, the trampoline nested function doesn't have access to the trampoline variables, in this case the float, 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;
}
4
  • 2
    Nested functions is not a standard C feature. So it is better not to use them. Commented Feb 16, 2021 at 8:58
  • 2
    Depends on the context. If there is commitment about using non standard stuff for some reason. E.g. all of the team uses the gcc toolchain, what about using gcc extensions (nested functions is infact such a feature)?. Commented Feb 16, 2021 at 9:00
  • Well this is roughly like accessing a local variable outside its scope... Docs says If you try to call the nested function through its address after the containing function exits, all hell breaks loose. Commented Feb 16, 2021 at 9:10
  • Maybe you should consider switching to C++17. It is a very complex language, but it has lambda expressions and std::function and with a lot of care you could write a library in C++ callable from C code (an example being libgccjit...) Commented Feb 18, 2021 at 14:04

2 Answers 2

2

From gcc documentation nested functions:

If you try to call the nested function through its address after the containing function exits, all hell breaks loose.

The function void foo is defined inside function Wrapper and the address to the function foo is returned from Wrapper. Then you call the function after the function Wrapper exits. As documentation states your code makes "all hell break loose".

Think of a nested function as a variable allocated on stack. When the function returns, the nested function stops existing.

the trampoline nested function can't access to the trampoline variables, in this case the float r.

The variable r has scope only within Wrapper function. Once Wrapper exits, the variable r stops existing.

auto void foo();
auto void foo2();

That's odd. There's no need to write that. Just write the function - it's like auto by default anyway.

Sign up to request clarification or add additional context in comments.

Comments

1

You cannot use c() once Wrapper() has finished, because it is out of scope. Think of it as if that function existed only while Wrapper() was being executed (even if you know that it's code is still somewhere, you cannot execute it for the reasons explained below, if it is not from the inside of the function that contains it) You call Wrapper() in the beginning of main(), and Wrapper() returns a pointer to a function that is local to Wrapper(). Well, that pointer is a fake pointer because the function has ceased to exist as soon as the program returned from Wrapper. This is like returning a pointer to a local variable.

I should say Undefined Behaviour, but as we are talking about a GCC extension, that term is out of scope also, so what can I say then? (As I have seen from the other answer by KamilCuk, GNU uses the term all hell breaks loose, which sounds perfect for me)

The implementation of nested functions means using displays (arrays of pointers to the closest active call records of all the nested functions out of this one, this is done in other languages, like Pascal, Ada or Modula-2) to access the scoped identifiers in outer functions, like you do, when you access the float r from c(), but later, when Wrapper is not being executed, no display exists of the local variables in Wrapper() and the call to c() is in error because the access to the value 1.0 has gone long ago.

For all purposes, your trick to try to call c() out of scope (outside of Wrapper()) is illegal, and I don't know why can you require this, but you are wrong if you thought you can maintain a local resource (like the parameter r in Wrapper, after the call to the function that used it has return)

I suggest you to have a look to the array of nested function pointers and how the compiler access to variables on the outer function through the display, by looking at the assembly code of the nested functions (you can nest indefinitely, and at each level of nesting you add one more pointer to the vector) In standard C there are no displays, because all the functions are defined at top level.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.