2016-06-17 2 views
0

Можно ли «обернуть» указатель на функцию C каким-то образом, подобно тому, что вы сделали бы с лямбдой в C#?Как обернуть указатель функции в plain C

Реальная проблема я имею:

У меня есть несколько функций с различными параметрами:

// 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++ Я хотел бы использовать лямбда, или указатель на метод, который назвал бы другой, но я понятия не имею, как это сделать в C, если я вручную создавать функции оболочки:

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

Есть ли другой способ избежать этого шага?

+3

Нет, не совсем. – melpomene

ответ

1

Вы можете создать структуру, которая будет содержать тип функции, указатель функции и аргументы, если необходимо. Функция Thread должна будет проверять тип функции, а затем вызывать функцию, используя соответствующие параметры сигнатуры и прохода, хранящиеся в структуре. Вы также можете создавать вспомогательные функции, используемые для создания этих структур для упрощения кодирования. Ниже приведен пример кода для двух возможных типов функций (с 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; 
} 
3

Нет, нет другого способа, кроме как создать функции обертки. И помните, что они тоже должны вернуть значение. Если вы не завершаете (или забываете вернуть значение (фиктивное)), вы получите UB.

+0

Вы правы, я только что заметил, что забыл вернуть значение в примере. +1 – Lou

 Смежные вопросы

  • Нет связанных вопросов^_^