Reputation: 33
#include <stdio.h>
int (*function_factory(int outer_args))(int){
int returned_function (int inner_args){
return outer_args + inner_args;
}
return &returned_function;
}
int main(void){
printf("%d\n",function_factory(1)(2));
return 0;
}
When I try to compile the above code with the -pedantic and -Werror flags, I get the error error: ISO C forbids nested functions
. For the purposes of my task, assume I can't remove those two flags. Is there a way I can return a function that will take inner_args while still having access to outer_args?
Upvotes: 1
Views: 247
Reputation: 215387
No. The C language does not have nested functions, and even the "GNU C" extension for them does not allow you to call them after the enclosing function invocation has ended.
The correct and portable way to do this is in C is with a pair (possibly stored in a struct, if you like) of function pointer and pointer to struct containing the context. The context can then be allocated on the stack of the "enclosing function invocation" if you won't use the context after the invocation ends; otherwise, it can live in allocated storage (malloc
) which you explicitly free when done with it.
Such a pair cannot be passed to interfaces which only take a function pointer, but good APIs using function pointers also take a (usually void *
) context argument to be passed back to the function.
Upvotes: 0
Reputation: 58617
Although GNU C does support nested functions, it will not work anyway. Nested functions in GNU C are "downward funarg only". They are not lexical closures; everything is on the stack. When the parent of a nested function terminates, that function becomes garbage; using the returned function pointer outside of that scope is not well-defined.
(GNU C local functions also require an executable stack. They fit the downward closure into a regular C function pointer, which requires the construction of piece of machine code on the stack called a "trampoline".)
To simulate lexical closures in standard C, you have to hoist all the function bodies to file scope (no nesting) and use an explicit closure data structure which holds a pointer to the code and to the captured environment:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
struct counting_closure {
/* simulated captured environment */
int count;
/* pointer to code */
int (*lambda)(struct counting_closure *);
};
int counting_lambda(struct counting_closure *clo)
{
/* simulated access to captured lexical */
return clo->count++;
}
struct counting_closure *make_counter(int start)
{
struct counting_closure *clo = malloc(sizeof *clo);
clo->count = start;
clo->lambda = counting_lambda;
return clo;
}
int main(void)
{
struct counting_closure *cntr = make_counter(1);
printf("%d\n", cntr->lambda(cntr));
printf("%d\n", cntr->lambda(cntr));
printf("%d\n", cntr->lambda(cntr));
free(cntr);
return 0;
}
Upvotes: 4
Reputation: 29266
You can't have nested functions but you can return a function pointer:
typedef int (*FuncPtr)(void);
int sample(void){
return 1;
}
FuncPtr choose(int f)
{
if (f == 1) return sample;
return NULL;
}
main()
{
FunPtr p = choose(1);
if (p) { printf("%d\n", p()); }
return 0;
}
Upvotes: 0