如何使用调用堆栈传递函数指针?

时间:2013-04-24 17:25:29

标签: c

我不确定我是否拥有这个问题的最佳标题,随时可以改进。

如果我有

typedef void (*VoidFunction)(void);

然后是一系列适合这种类型的函数,我可以编写一种类似于“事务”的包装函数:

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

如果我有一系列带有单个int参数的函数,我可以冲洗 - 重复:

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

抛出返回类型的问题(iow,假设为void返回类型),是否可以对这个模式进行泛化,这样我只需编写一个包装函数,如:

// ????? 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();
}

3 个答案:

答案 0 :(得分:2)

如果您想使用{{1>}语法(称为可变参数),则使用...访问参数列表,例如:

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

答案 1 :(得分:0)

  

我不确定如何键入传递的函数

就像你在其他任何地方声明一个函数指针一样:

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

我不知道怎么称呼它......

就像你已经做过的那样:

function();

答案 2 :(得分: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);
}