使用var_arg为函数调用传递参数

Using var_arg to pass parameters for function calls

本文关键字:参数 函数调用 var arg 使用      更新时间:2023-10-16

我正在编写一个适配器来组合两个API(一个在C中,另一个在C++中)。如果在一个API上调用函数,我需要将调用方ID和函数的参数传递给适配器,并使用传递的信息调用相应的函数。

现在,它们通常不能直接映射,因为一个接口需要C++编译,而名称篡改会破坏另一个接口,所以这就是我首先使用一组适配器的原因。

由于参数的数量不同,我查找了可变函数,发现这个想法非常有用,但我只在POD上操作,每次调用都必须处理结构、枚举和许多不同的参数,这些参数可能需要放回结构中,然后再将其提供给目标函数。

我偶然发现的每一个例子都要简单得多,主要涉及算术运算,比如求和、求最大数或打印。主要使用var_list上的for循环完成。

也许我被这个想法卡住了,它根本不起作用,但我只是好奇。。。

假设我想将列表中的参数分配给我的目标函数参数(传递的参数的顺序是正确的),有什么好方法?

BOOL Some_Function(
    /* in  */ CallerId *pObjectId,
    /* in  */ someDataType argument1 )
{
    BOOL ret = Adapter_Call(pFunction, pObjectId, argument1);
    return ret;
}

所以一旦我找到合适的适配器,我就想做

BOOL Adapter_Call(*pFunction, *pObjectId, argument1, ...)
{
  va_list args;
  va_start(args, argument1);
  /*go over list and do `var_list[i] = pFunctionArgList[i]` which is  
    of whatever type so I can use it as input for my function */
  va_end(args);
  pObjectId.pFunction(arg1,...,argn);
}

我可以访问函数的输入参数来执行这样的分配吗?以前有人做过这样的事吗?我的想法有概念上的错误吗?

我在网上找到的只有这个,http://www.drdobbs.com/cpp/extracting-function-parameter-and-return/240000586but由于使用了模板,我不确定它是否会产生另一个问题,因此最终为每个函数调用实现一个适配器可能会更简单。

SO搜索只返回以下内容:运行时动态函数调用(va_list)

首先,您应该听取Kerrek关于extern "C"的建议。这是C++提供标识符C链接的机制,这意味着C++编译器不会损坏名称。

有时,和适配器仍然需要为C++接口编写,因为它处理的对象不映射到C POD。因此,适配器为C接口提供了一个POD或不透明指针类型来操作,但该接口的实现将其转换为C++对象或引用,然后调用C++接口。例如,假设您想为C++std::map<int, void *>提供一个C接口,那么在C和C++中会有一个公共头文件,其中包含:

#ifdef __cplusplus
extern "C" {
#endif
    struct c_map_int_ptr;
    // ...
    // return -1 on failure, otherwise 0, and *data is populated with result
    int c_map_int_ptr_find (struct c_map_int_ptr *, int key, void **data);
#ifdef __cplusplus
}
#endif

然后,C++代码可以实现如下功能:

typedef std::map<int, void *> map_int_ptr;
int c_map_int_ptr_find (struct c_map_int_ptr *cmap, int key, void **data) {
    map_int_ptr &map = *static_cast<map_int_ptr *>(cmap);
    map_int_ptr::iterator i = map.find(key);
    if (i != map.end()) {
        *data = i->second;
        return 0;
    }
    return -1;
}

因此,不需要通过变量参数适配器传递通过C接口传递的参数。因此,C++代码不需要从变量参数列表中梳理出参数。C代码直接调用C++代码,C++代码知道如何处理参数。

我想,如果您试图通过解析C++代码来实现某种自动化的C适配器代码生成器,您可能会认为使用变量自变量将提供一种常规机制,在生成的C代码接口和调用原始C++接口的生成的C++适配器代码之间通信自变量。对于这样的场景,上面例子的代码看起来像这样:

// C interface
typedef struct c_map_int_ptr c_map_int_ptr;
typedef struct c_map_int_ptr_iterator c_map_int_ptr_iterator;
//...
c_map_int_ptr_iterator c_map_int_ptr_find (c_map_int_ptr *map, int key) {
    c_map_int_ptr_iterator result;
    cpp_map_int_ptr_adapter(__func__, map, key, &result);
    return result;
}
// C++ code:
struct cpp_adapter {
    virtual ~cpp_adapter () {}
    virtual void execute (va_list) {}
};
void cpp_map_int_ptr_adapter(const char *func, ...) {
    va_list ap;
    va_start(ap, func);
    cpp_map_int_ptr_adapter_method_lookup(func).execute(ap);
    va_end(ap);
}
//...
struct cpp_map_int_ptr_find_adapter : cpp_adapter {
    void execute (va_list ap) {
        map_int_ptr *map = va_arg(ap, map_int_ptr *);
        int key = va_arg(ap, int);
        c_map_int_ptr_iterator *c_iter = va_arg(ap, c_map_int_ptr_iterator *);
        map_int_ptr::iterator i = map->find(key);
        //...transfer result to c_iter
    }
};

其中cpp_map_int_ptr_adapter_method_lookup()基于表查找返回适当的cpp_adapter实例。