clambdafunction-pointerscreatethread

How to wrap function pointer in plain C


Is it possible to "wrap" a function pointer in C somehow, similar to what you would do with a lambda in C#?

Actual problem I am having is:

I have a couple of functions with different parameters:

// more than two in actual code
void DoStuff(void) { ... }
void DoOtherStuff(int) { ... }

...and I want to create a couple of threads to run these in a loop:

// this won't work because it expects a LPTHREAD_START_ROUTINE,
// which is int(*fn)(void*)
tHnd1 = CreateThread(NULL, 0, &DoStuff, NULL, 0, &tId);
tHnd2 = CreateThread(NULL, 0, &DoOtherStuff, NULL, 0, &tId);

In C#/C++ I would use a lambda, or a pointer to a method which would call the other one, but I have no clue how to do this in C, unless I manually create wrapper functions:

int CallDoStuff(void *dummy) { DoStuff(); return 0; }
int CallDoOtherStuff(void *dummy) { DoOtherStuff(42); return 0; }

Is there any other way to avoid doing this step?


Solution

  • You can create structure which will contain function type, function pointer and arguments if needed. Thread function would have to check function type and then call function using appropriate signature and pass parameters stored in structure. You can also create helper functions used to create these structures to simplify coding. Below is example code for two possible function types (with void and int arg):

    #include <stdio.h>
    #include <stdlib.h>
    
    /* Few types needed to store function pointer and arguments in struct */
    typedef enum FuncType
    {
        F_Void,
        F_Int,
    } FuncType;
    
    typedef void(*VoidFuncPtr)(void);
    typedef void(*IntFuncPtr)(int);
    
    typedef struct FuncWrapper
    {
        FuncType funcType;
        union
        {
            VoidFuncPtr voidFunc;
            IntFuncPtr intFunc;
        };
        union
        {
            int intArg;
        };
    } FuncWrapper;
    
    /* Thread func which can handle different functions */
    void ThreadFunc(void* arg)
    {
        FuncWrapper* wrapper = (FuncWrapper*)arg;
        switch (wrapper->funcType)
        {
        case F_Void:
            wrapper->voidFunc();
            break;
        case F_Int:
            wrapper->intFunc(wrapper->intArg);
            break;
        }
        free(wrapper);
    }
    
    /* Helper functions used to create FuncWrapper instances */
    FuncWrapper* wrapVoidFunc(VoidFuncPtr func)
    {
        FuncWrapper* wrapper = (FuncWrapper*)malloc(sizeof(FuncWrapper));
        wrapper->funcType = F_Void;
        wrapper->voidFunc = func;
        return wrapper;
    }
    
    FuncWrapper* wrapIntFunc(IntFuncPtr func, int arg)
    {
        FuncWrapper* wrapper = (FuncWrapper*)malloc(sizeof(FuncWrapper));
        wrapper->funcType = F_Int;
        wrapper->intFunc = func;
        wrapper->intArg = arg;
        return wrapper;
    }
    
    /* Dummy StartThread func, which simply calls passed in function */
    typedef void(*ThreadFuncPtr)(void*);
    void StartThread(ThreadFuncPtr funcPtr, void* data)
    {
        funcPtr(data);
    }
    
    /* Functions which will be called */
    void myVoidFunction(void)
    {
        printf("myVoidFunction called\n");
    }
    
    void myIntFunction(int arg)
    {
        printf("myIntFunction called, arg = %d\n", arg);
    }
    
    /* Finally the main func */
    int main()
    {
        StartThread(ThreadFunc, wrapVoidFunc(myVoidFunction));
        StartThread(ThreadFunc, wrapIntFunc(myIntFunction, 22));
        return 0;
    }