1

我正在编写一个适配器来组合两个 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/240000586但是由于使用了模板,我不确定它是否不会产生另一个问题所以最终为每个函数调用实现一个适配器可能会更简单。

SO 搜索只返回了这个:Dynamic function calls at runtime (va_list)

4

1 回答 1

1

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

有时,仍然需要为 C++ 接口编写适配器,因为它操作不映射到 C POD 的对象。因此,适配器为 C 接口提供 POD 或不透明指针类型以进行操作,但该接口的实现将其转换为 C++ 对象或引用,然后调用 C++ 接口。例如,假设您想为 C++ 提供一个 C 接口std::map<int, void *>,您将有一个 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 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
    }
};

Where根据表查找cpp_map_int_ptr_adapter_method_lookup()返回适当的实例。cpp_adapter

于 2013-08-23T18:43:06.747 回答