2013-04-24 2 views
2

Я не уверен, что у меня есть лучшее название для этого вопроса, не стесняйтесь улучшаться.Как передать указатели функций со стеком вызовов?

Если у меня есть

typedef void (*VoidFunction)(void); 

, а затем семейство функций, которые соответствуют этому типу, я мог бы написать что-то вроде «сделки» функции-оболочки, которая выглядела что-то вроде:

void doTransaction(VoidFunction function) 
{ 
    doSomePreambleWork(); 
    function(); 
    doSomePostambleWork(); 
} 

Если я имел семейство функций, которые принимали однократные аргументы, я мог бы промывать-промыть-повторить:

typedef void (*VoidOneIntFunction)(int a); 
void doTransactionOneInt(VoidFunctionOneInt function, int a) 
{ 
    doSomePreambleWork(); 
    function(a); 
    doSomePostambleWork(); 
} 

Lea Винг вопрос типов возврата (IOW, предполагая, что тип возвращаемого недействительным), является возможным genericize эту модель, так что я только должен сделать написать одну функцию-обертку, что-то вроде:

// ????? I'm not sure how i'd type the passed function 
void doTransactionGeneric(void * function, ...) 
{ 
    doSomePreambleWork(); 
    function(); // ????? and i don't know how i'd go about calling it... 
    doSomePostambleWork(); 
} 
+0

Посмотрите на '' заголовка. Решение состоит в том, чтобы использовать список переменных аргументов. – Will

+0

@ Не думаю, что это то, о чем просит ОП. – 2013-04-24 17:29:06

+0

Я надеялся на что-то более «мета», чем на эти ответы. Возможно, это невозможно с C.Я думал, что могу каким-то образом связать со стеклом, чтобы вызвать первый аргумент стека вызовов (известный как функция), а оставшаяся часть стека вызовов волшебным образом. :( –

ответ

0

Я не уверен, как я бы ввести переданную функцию

Так же, как вы бы объявить указатель на функцию в другом месте:

void doTransactionGeneric(void (*function)(void), ...) 

, и я не знаю, как бы я идти о назвав его ...

Так же, как вы уже сделали:

function(); 
+0

Если вы объявите такую ​​функцию, вы не сможете передавать вариационные параметры самому 'doTransactionGeneric()' и передавать их вместе с указанной функцией. –

2

Если вы хотите использовать ... синтаксис, известный как VARIADIC параметры, то вы используете va_list для доступа к списку параметров, например:

#include <stdarg.h> 

typedef void (*VoidArgsFunction)(va_list args); 

void doTransactionGeneric(VoidArgsFunction function, ...) 
{ 
    doSomePreambleWork(); 

    va_list args; 
    va_start(args, function); 
    function(args); 
    va_end(args); 

    doSomePostambleWork(); 
} 

Внутри вызываемой функции, он может использовать va_arg(), чтобы получить доступ к отдельным значения параметров из va_list по мере необходимости, например:

#include <stdarg.h> 

void someFunction(va_list args) 
{ 
    int param1 = va_arg(args, int); 
    char *param2 = va_arg(args, char*); 
    ... 
} 

doTransactionGeneric(&somefunction, 12345, "Hello World"); 
0

Вот предложение.

Если у вас есть несколько функций (например, в вашем вопросе):

typedef void (*VoidFunction)(void); 
typedef void (*VoidFunctionOneInt)(int); 
// we can add more 

Определим тип перечисления (мы не должны использовать перечисление, но это нагляднее):

typedef enum 
{ 
    e_fn_void,  // void return, no args 
    e_fn_void_int, // void return, one int 
        // we can add more... 
} void_function_kind_t; 

Затем, скажем, у нас есть общий процессор. Мы должны поставить тип функции, указатель функции и аргументы:

void some_generic_function(void_function_kind_t kind, void *fn, ...) 
{ 
    va_list args; 
    va_start(args, fn); 

    // here - make a call 
    switch (kind) 
    { 
    case e_fn_void: 
     // no arguments 
     ((VoidFunction)fn)(); 
     break; 
    case e_fn_void_int: 
     { 
      int arg0 = va_arg(args,int); 
      ((VoidFunctionOneInt)fn)(arg0); 
     } 
     break; 
    default: // error - unsupported function type 
     break; 
    } 

    va_end(args); 
} 
Смежные вопросы