如何在纯 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;
}
是否有可能以某种方式在 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;
}