首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C中创建使用C++代码的包装器?

如何在C中创建使用C++代码的包装器?
EN

Stack Overflow用户
提问于 2019-06-05 23:43:11
回答 3查看 1.9K关注 0票数 4

我试图为一个C++第三方库做一个C包装,因为我需要在我的C项目中使用它。我看过C++类包装器的例子,但是我不理解这个过程,也不能包装C++结构。

结构,我想包装:

代码语言:javascript
复制
struct confGlobal{
    long int device;
    string name;
    int number;
    string uid;
    string message;
    bool mode;

    confiGlobal():device{LONG_MAX}, number{INT_MAX}{}
};

struct product{
    string id;
    string name;
};
struct category{
    unsigned char id;
    string name;
    string description;

    category():id{UCHAR_MAX}{}
};
struct subCategory{
    unsigned char id;
    string name;
    string description;
    unsigned char idRoot;

    subCategory():id{UCHAR_MAX}, idRoot{UCHAR_MAX}{}
};
struct confPartner{
    vector<struct product> tableProduct;
    vector<struct category> tableCategory;
    vector<struct subCategory> tableSubCategory;
};

对于此方法的调用:

代码语言:javascript
复制
class my_API {
public:
    static my_API* Instance(struct confGlobal cGlobal,
                        struct confPartner cPartner);
   ... another methods ...
private:
    virtual ~my_API();
    struct confGlobal cGlobal;
    struct confPertner cPartner;
};

我需要填充这个结构并从C调用my_API::Instance(),但是我的尝试没有成功。

wrapper.h

代码语言:javascript
复制
#ifdef __cplusplus
extern "C" {
#endif
struct confGlobal_wpr; // An opaque type that we'll use as a handle
typedef struct confGlobal_wpr confGlobal_wpr;
confGlobal_wpr *confGlobal_create(unsigned int device,
                     char *name,
                     int number,
                     char *uid,
                     char *message,
                     unsigned char mode);

struct product_wpr{
    char id[4];
    char name[30];
};
typedef struct product_wpr product_wpr;

struct category_wpr{
    unsigned char id;
    char name[3];
    char description[30];
};
typedef struct category_wpr category_wpr;

struct subcategory_wpr{
    unsigned char id;
    char name[3];
    char description[30];
    unsigned char idRoot;
};
typedef struct subCategory_wpr subCategory_wpr;
struct confPartner_wpr; // An opaque type that we'll use as a handle
typedef struct confPartner_wpr confPartner_wpr;
confPartner_wpr *confPartner_create(Product_wpr tableProducts[],
                     unsigned char numProducts,
                     Category_wpr tableCategories[],
                     unsigned char numCategories,
                     SubCategory_wpr tableSubCategories[],
                     unsigned char numSubCategories);

struct my_api_wpr;
typedef struct my_api_wpr my_api_wpr;

my_api_wpr *my_api_create(struct confGlobal_wpr cGlobal,
                     struct confPartner_wpr cPartner);

#ifdef __cplusplus
}
#endif

wrapper.cpp

代码语言:javascript
复制
confGlobal_wpr *confGlobal_create(unsigned int device,
                     char *name,
                     int number,
                     char *uid,
                     char *message,
                     unsigned char mode)
{
    confGlobal_wpr *cg;
    struct confGlobal confiGlobal;
    confiGlobal.name = name;
    confiGlobal.device = device;
    confiGlobal.number = number;
    confiGlobal.uid = uid;
    confiGlobal.message = message;
    if (mode == 0)
        confiGlobal.mode = false;
    else
        confiGlobal.mode = true;
    return cg;
}
void confGlobal_destroy(confGlobal_wpr *cg)
{
    if (cg == NULL)
        return;
    delete static_cast<confGlobal_wpr *>(cg->instance); // ERROR: invalid static_cast from type ‘confGlobal’ to type ‘confGlobal_wpr*’
    free(cg);
}

confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
                     unsigned char numProducts,
                     category_wpr tableCategories_wpr[],
                     unsigned char numCategories,
                     subCategory_wpr tableSubCategories_wpr[], 
                     unsigned char numSubCategories)
{
    unsigned char i=0;

    confPartner_wpr *cc;
    struct confPartner cPartner;
    vector< struct product> tableProduct;
    vector< struct category> tableCategory;
    vector< struct subCategory> tableSubCategory;

    for (i=0; i<numProducts; i++)
    {
        struct product p;
        p.id = tableProducts_wpr[i].id;
        p.name = tableProducts_wpr[i].name;
        tableProduct.push_back(p);
    }
    cPartner.tableProduct = tableProducts;

    for (i=0; i<numCategories; i++)
    {       
        struct category c;
        c.id = tableCategories_wpr[i].id;
        c.nombre = tableCategories_wpr[i].name;
        c.descripcion = tableCategories_wpr[i].description;
        tableCategory.push_back(c);
    }
    cPartner.tableCategory = tableCategory;

    for (i=0; i<numSubCategories; i++)
    {
        struct subZona sc;
        sc.id = tableSubCategories_wpr[i].id;
        sc.name = tableSubCategories_wpr[i].name;
        sc.description = tableSubCategories_wpr[i].description;
        sc.idRoot = tableSubCategories_wpr[i].idRoot;
        tableSubCategory.push_back(sc);     
    }
    cPartner.tableSubCategory = tableSubCategory;
    return cc;

}

my_api_wpr *my_api_create(struct confGlobal_wpr confiGlobal_wpr,
                      struct confPartner_wpr confiPartner_wpr)
{
    my_api_wpr *my_api;
    my_API *obj;
    my_api = (typeof(my_api))malloc(sizeof(*my_api));
    obj    = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
    /* With this compile and linked OK
    confGlobal cg;
    confPartner cc;
    obj    = my_API::Instance(cg, cc);
    */
    my_api->obj = obj;

    return my_api;
}
void my_api_destroy(ct_api_wpr *my_api)
{
    if (my_api == NULL)
        return;
    delete static_cast<my_API *>(my_api->ptr_api); // ERROR: ‘virtual my_API::~my_API()’ is private within this context
    free(my_api);
}

编译和链接时的输出错误:

代码语言:javascript
复制
g++ -shared -o libwrapper.so *.cpp wrapper.h -l:libthird-party.a -L. -ldl -lrt -Wl,-rpath /usr/local/lib -lc
代码语言:javascript
复制
In function ‘my_api_wpr* my_api_create(confGlobal_wpr, confPartner_wpr)’:
error: no matching function for call to ‘my_API::Instance(confGlobal_wpr&, confPartner_wpr&)’
  obj    = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
                                                               ^
my_API.h:30:20: note: candidate: static my_API* my_API::Instance(confGlobal, confPartner)
     static my_API* Instance(struct confGlobal cGlobal, struct confiPartner cPartner);
                    ^~~~~~~~
my_API.h:30:20: note:   no known conversion for argument 1 from ‘confGlobal_wpr’ to ‘confGlobal’
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-06 00:23:11

您忘记了,CT_API::Instance不理解在C中为包装C++结构而创建的“句柄”类型。这正是错误信息告诉你的,如果你读了它。您必须将这些转换回适当的C++类型。

首先,由于使用“创建”-style例程来构建结构并将它们作为指针返回,因此应该考虑让my_api_create函数接受指针。特别是因为生成的句柄类型是前向声明的结构,在C中没有可见的定义,而且您的C客户端不可能取消它们的引用。

这突出了另一个问题。您也没有从C++正确地使用这些句柄。

所以一件事一件一件。

您在C中的创建例程应该声明为:

代码语言:javascript
复制
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner);

在C++方面,您需要实际定义句柄类型。类似于:

代码语言:javascript
复制
extern "C" struct confGlobal_wpr {
    struct confGlobal instance;
};

extern "C" struct confPartner_wpr {
    struct confPartner instance;
};

extern "C" struct my_api_wpr {
    my_API *ptr;
};

现在,你的创作:

代码语言:javascript
复制
confGlobal_wpr *confGlobal_create(unsigned int device,
                                  char *name,
                                  int number,
                                  char *uid,
                                  char *message,
                                  unsigned char mode)
{
    confGlobal_wpr *cg = new confGlobal_wpr;
    struct confGlobal& cGlobal = cg->instance; //<-- note the reference
    // TODO: populate cGlobal as usual
    return cg;
}

confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
                                    unsigned char numProducts,
                                    category_wpr tableCategories_wpr[],
                                    unsigned char numCategories,
                                    subCategory_wpr tableSubCategories_wpr[],
                                    unsigned char numSubCategories)
{
    confPartner_wpr *cc = new confPartner_wpr;
    struct confPartner& cPartner = cc->instance; //<-- note the reference
    // TODO: populate cPartner as usual
    return cc;
}

my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner)
{
    my_api_wpr *my_api = new my_api_wpr;
    my_api->ptr = CT_API::Instance(cGlobal->instance, cPartner->instance);
    return my_api;
}

您还应该为上述所有内容添加相应的_destroy方法。

票数 2
EN

Stack Overflow用户

发布于 2019-06-06 00:30:16

要在C项目中使用C++代码,您需要使用C调用约定- extern“C”定义包装函数(关闭C++名称mangling/装饰性),并在C项目中调用它们,并且只调用它们。在这些C函数中,您可以使用C++代码。传递给C包装函数,只有C理解的类型。您可以创建将数据传递给C包装函数的中间结构。然后,您需要将数据复制到C++类所期望的类型。在您的特殊情况下,您不正确地传递confGlobal_wpr包装器结构,但是C++方法需要confGlobal,编译器直接对此进行抱怨。

下面是如何使用C代码中的C++代码的可观察到的代码片段: Foo.h

代码语言:javascript
复制
#include <string>

class Bar
{
public:
    Bar(std::string s) : s_(s)
    {
    }
    std::string s_;
};

class Foo
{
public:
    Foo(Bar) {}
};

H //将此头包含到C项目中。

代码语言:javascript
复制
struct BarWrapper
{
    char data[100] = "";
};

#ifdef __cplusplus
extern "C" {
#endif

BarWrapper createFoo(char *c);

#ifdef __cplusplus
}
#endif

Wrapper.cpp

代码语言:javascript
复制
#include <algorithm>

#include "Foo.h"
#include "CWrappers.h"

// input and output to this C function should be understandable for C
BarWrapper createFoo(char *c)
{
    // inside you can use C++
    std::string data(c);
    Bar bar(data);
    Foo * foo = new Foo(bar);
    BarWrapper barWrapper;
    std::copy(data.begin(), data.end(), barWrapper.data);
    return barWrapper; // pack data to C struct wrapper (that has no C++ specific)
}

C项目

代码语言:javascript
复制
        #include "CWrappers.h"

        int main()
        {
            BarWrapper barWrapper = createFoo((char *)"test");
        }
票数 2
EN

Stack Overflow用户

发布于 2019-06-06 00:02:48

除了C和C++共有的原始数据类型之外,包含其他任何内容的结构很大程度上不能以您想要的方式包装。在这种情况下,您的结构中有::std::strings。而且绝对不能从C中合理地访问它们。

此外,这些结构包含bool,我不知道新版本的C标准是否有bool,也不知道定义它的方式是否会导致布局兼容的结构与同一个平台上的C++实现兼容。

解决这个问题是有办法的。但是,它们涉及使用C中指向结构的不透明指针,并且总是调用函数来访问其方法。我将尝试给出一个例子,说明这对于一个非常简单的结构是如何工作的。

仔细观察您的代码,您似乎需要一种thunk层,它接受C结构并(在C++中)将其转换为C++结构,并返回一个指向动态分配的C++结构的指针,然后您可以将该指针传递给其他已公开给C的C++函数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56469366

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档