【问题标题】:C: Passing any function to a functionC:将任何函数传递给函数
【发布时间】:2017-12-13 12:03:46
【问题描述】:

我想知道如何将任何函数传递给函数,就像在一个可以接受任何函数的通用函数指针中一样,这样做的目标是创建一个析构函数系统,所以基本上存储函数和使用它的参数调用它也存储在后面的行中,

类似:

Defer(SDL_DestroyWindow, Window); 

我已经处理了参数,但是我不知道如何管理这个函数指针部分,谢谢!

编辑:我添加了更多信息...

typedef struct {
  void** args;
} IM_Defer_Resource;
/* Defer & Whatnot */

IM_Stack* IM_Defer_Stack;

void IM_Defer_Init() {
  IM_Defer_Stack = IM_Stack_Init();
}


void IM_Defer(/* What to put here? */) {

}

void IM_Defer_All() {
  while(IM_Defer_Stack->size) {
    IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
    if(!resource) continue;
    /* What to do */
  }
}

我没有defer的实际功能,但是我确实将每个参数都复制到堆栈中并且可以成功弹出它们,但我不知道如何实现可变参数函数调用

编辑2: 收到一些输入后:我认为这会更可行: Defer(SDL_DestroyWindow, "SDL_Window*", window); 我正在集思广益,这将如何成为可能,但我希望能提供一些意见

编辑3:

/* Defer & Whatnot */
typedef struct {
  char** types;
  void** args;
  int count;
} IM_Defer_Resource;


IM_Stack* IM_Defer_Stack;

void IM_Defer_Init() {
  IM_Defer_Stack = IM_Stack_Init(IM_Get_Stack_Type(IM_Defer_Resource));
}

void IM_Defer_Internal(void* var, int n, ...) {
  char* type;
  void* arg;

  va_list args;
  va_start(args, n);

  IM_Defer_Resource resource;
  int count = n / 2;
  resource->types = calloc(count, sizeof(char*));
  resource->args = calloc(count, sizeof(void*));
  resource->count = count;

  for(count > 0; n -= 1) {
    type = va_arg(args, char*);
    resource->types[count-1] = type;
    arg = va_arg(args, void*);
    resource->args[count-1] = arg;
  }

  IM_Stack_Push(IM_Defer_Stack, &resource);
}

void IM_Defer_All() {
  while(IM_Defer_Stack->size) {
    IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
    if(!resource) continue;
    /* I have a char* and a void* to the resource, Now what? */
    free(resource->types);
    free(resource->args);
  }
}

这是我想出的,但我想知道如何将 char* 转换为类型...

【问题讨论】:

  • 你也许可以用可变参数宏技巧做一些事情,虽然我对此很生疏;)
  • 任何一种类型的函数指针都可以转换为另一种类型的函数指针。因此使用foo(int (*f)()) { ... } 足以传递函数指针()。诀窍是如何传递 type。代码对有限类型列表使用union 和枚举值 - 但 any 类型? --> 建议缩小目标。
  • @chux - 那么问题是如何将可变数量的参数传递给(非可变)函数指针。
  • "我已经处理了参数" --> 发布你的代码可以让你的目标更加清晰。
  • 可能有,正如我所说,但非常非常复杂。如果您有支持 C11 的编译器,您还可以尝试使用 _Generic 进行通用选择,制作一组包含一组参数的包装函数,这些参数可以适合您想要使用的任何类型的函数,然后仅使用本地调用函数适当的参数。考虑到这是人们选择 C++ 的原因之一......

标签: c function pointers function-pointers generic-programming


【解决方案1】:

正如我在评论中所说,一个大问题是在声明可变参数函数时,未声明的参数受default argument promotions 的约束。这意味着您可以发现传递的参数与函数预期的参数不同,这最终会导致异常。你想做的事情是可行的,但是真的很复杂。

一种解决方案,但由于需要大量编码而受到限制,可能是:

#include <stdarg.h>
#include <stdio.h>

typedef enum { fn1, fn2, fn3, /*....*/} e_fn;

void multi_fun(e_fn fn, ...)
{
    va_list ap;
    int j;

    va_start(ap, fn); /* Requires the last fixed parameter (to get the address) */

    switch(fn)
    {
        case fn1:
        {
            //suppose prototype for fn1 to be void fn1_fn(int, float, struct  mystruct *);
            int   this_int   = va_arg(ap, int);
            float this_float = va_arg(ap, float);
            struct  mystruct *this_struct = va_arg(ap, struct  mystruct *);
            fn1_fn(this_int, this_float, this_struct);
            break;
        }

        case fn2:
        {
            ...
        }
    }
    va_end(ap);
}

【讨论】:

    【解决方案2】:

    您应该查看 GitHub 上的 Fake Function Framework (fff)。他们使用宏来缓存模拟函数。麻省理工学院许可。但是,就像@Frankie_C 所说,这需要大量代码。定义所有宏的头文件大约为 6K LOC。并且函数仍然限制为 20 个参数。

    【讨论】:

      猜你喜欢
      • 2015-05-02
      • 1970-01-01
      • 2018-11-14
      • 2013-06-26
      • 2014-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多