如何在纯 C 中包装函数指针

How to wrap function pointer in plain C

是否有可能以某种方式在 C 中 "wrap" 函数指针,类似于您在 C# 中对 lambda 所做的事情?

我遇到的实际问题是:

我有几个参数不同的函数:

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

...我想创建几个线程来循环 运行 这些:

// 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);

在 C#/C++ 中,我会使用 lambda,或指向调用另一个方法的指针,但我不知道如何在 C 中执行此操作,除非我手动创建包装函数:

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

有没有其他方法可以避免执行此步骤?

不,除了创建包装器函数之外真的没有其他方法。请记住,它们也必须 return 一个值。如果您不换行(或忘记 return 一个(虚拟)值),您将拥有 UB。

如果需要,您可以创建包含函数类型、函数指针和参数的结构。线程函数必须检查函数类型,然后使用适当的签名调用函数并传递存储在结构中的参数。您还可以创建用于创建这些结构的辅助函数以简化编码。下面是两种可能的函数类型(带有 void 和 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;
}