Search code examples
cnested-function

Can I somehow use nested functions in ANSI C?


I have background with high level languages, such as Java/Kotlin/Scala. Now I need to create a C library, but it's pretty hard for me to work without closures.

There is the nice extension in GCC, called "nested functions", that (if I correctly understood) is exactly what I need. Also the Apple "blocks" extension looks interesting. But I need a code, that will work with any compiler.

Does any existing solution present? I've seen some projects, that allow generating C code: https://github.com/dbohdan/compilers-targeting-c. But I really don't need another language, just one feature - closures. (I think that it hard to maintain completely different language and result C code will be not optimized).

UPD Some explanation, why do I need closures.

Let say we have some function, connect(void (*on_failed_callback)());. It manages a connection in some way, and when the connection is lost, it calls the callback. And it takes 0 arguments, but I want to create some function that will bring some data with callback. If I've correctly understood, the most common used solution is to pass the callback with some arg connect(void (*on_failed_callback)(void *callback_arg), void* arg);. But it leads to a boilerplate code, that can be fixed by nested functions.

So next code:

void connect(void (*on_failed_callback)(void* arg), void* arg) {
    ...
    on_failed_callback(arg);
}

void print_error(char* error) {
    printf(error);
}

void main() {
    char *msg = "Failed connection";
    ...
    connect(print_error, msg);
}

Can be simplified to next:

void connect(void (*on_failed_callback)()) {
    ...
    on_failed_callback();
}

void print_error(char* error) {
    printf(error);
}

void main() {
    char* msg = "Failed connection";
    ...
    void callback() {
       print_error(msg);
    }
    connect(callback);
}

I mean, I want some tool/app, that analyzes my code with closures/nested functions and generates pure ANSI C code.


Solution

  • For the specific example you have asked about there is an approach with C that achieves something similar to a closure in that it packages a function pointer with the data needed to be used with the function.

    typedef struct {
        char sBuff[128];              // data for the function to use
        void (* func) (char* error);  // pointer to function to execute
    } ErrorMsg;
    
    void connect(ErrorMsg myMsg) {
        ...
        myMsg.func(myMsg.sBuff);  // call the function with the packaged data
    }
    
    // the function that we will be encapsulating with the data to be
    // used.
    void print_error(char* error) {
        printf(error);
    }
    
    void main() {
        ErrorMsg msg = {"Failed connection", print_error} ;
        …
        connect(msg);  // invoke our function package and its data.
    }
    

    And if at the time that the function package is used, you would like to add additional data, you could do so along the lines of the following.

    typedef struct {
        char sBuff[128];              // packaged data for the function to use
        void (* func) (char* error, int iExtra);  // pointer to function to execute
    } ErrorMsg;
    
    void connect(ErrorMsg myMsg) {
        ...
        myMsg.func(myMsg.sBuff, errno);  // call the function with the packaged data and extra info
    }
    
    // the function that we will be encapsulating with the data to be
    // used.
    void print_error(char* error, int iExtra) {
        printf(error, iExtra);
    }
    
    void main() {
        ErrorMsg msg = {"Failed connection: errno %d", print_error} ;
        …
        connect(msg);  // invoke our function package and its data.
    }