如何在普通C中包装函数指针

时间:2016-06-17 16:04:16

标签: c lambda function-pointers createthread

是否有可能以某种方式在C中“包装”一个函数指针,类似于你在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; }

还有其他方法可以避免这一步吗?

2 个答案:

答案 0 :(得分:3)

不,除了创建包装函数之外别无他法。并记住他们也必须返回一个值。如果你没有包裹(或忘记返回(虚拟)值),你将拥有UB。

答案 1 :(得分:1)

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