Nested functions in GCC

GCC supports “nested functions” using the -fnested-functions flag. When I first saw this, I was excited: closures in C! In the famous words of Admiral Ackbar, “it’s a trap!”

#include 

typedef int (*fptr)(int);

fptr f(int arg) {
  int nested_function(int nested_arg) {
    return arg + nested_arg;
  }

  return &nested_function;
}

void smash(int arg) {
  return;
}

int main(void) {
  fptr g = f(10);
  printf("%d\n", (*g)(5));
  smash(12);
  // printf("%d\n", (*g)(5));
  fptr h = f(12);
  printf("%d\n", (*g)(5));
  printf("%d\n", (*h)(5));

  return 0;
}

Try compiling (gcc -fnested-functions). What does the second call to g produce—15 or 17? Try uncommenting line 21. What happens? Does commenting out line 20 affect this? What if line 19 is commented out, but lines 20 and 21 are uncommented?

I’m not sure this feature is worth it.

5 Comments

  1. But it’s C; the compiler isn’t going to do any transformations like closure- or assignment conversion that could violate the transparency of the cost model. The compilation model is simple: a nested function is a function pointer with access to the frame pointer of its lexical parent function.

    And the manual does explicitly say “If you try to call the nested function through its address after the containing function has exited, all hell will break loose.” ;-)

    1. Hadn’t had a look at the manual (figures, doesn’t it?), so I suppose all of these behaviors are out of spec anyway. What troubles me about this is the existence of weird out of spec behaviors that are sometimes correct. That, I suppose, is where your “but it’s C” comment comes in. Point taken. :)

  2. How did you get it compiled in that day? My Eniac GCC does not like this option -fnested-function or -fnested-functions:

    cc1: error: unrecognized command line option “-fnested-function”
    cc1: error: unrecognized command line option “-fnested-functions”

  3. Is your laptop on Mac? If so, this might be the reason… Because I think nested-function is only working with Mac now, it basically comes from ‘block function’ in ObjectC.

    I just wanted to know how the local variables in the closure are stored. From your code, every time f is called, a fresh function pointer to that nested function is returned, where the local variables on f’s stack must be stored some where. I guess they must be on heap. But how is this memory space on heap released? since there is no GC in GCC, if we call f’ zillions of times, will it use all of the memory space…?

Leave a Reply

Your email address will not be published. Required fields are marked *