当前位置: 首页 > 知识库问答 >
问题:

SWIG:以面向对象的方式包装C-API

艾哲
2023-03-14

我有一个C(而不是C)库,它一致地使用函数的第一个参数作为上下文对象(让我们调用类型t_context),我想使用SWIG生成C#wrappers来保持这种调用风格(也就是说,不要把函数或多或少地孤立起来,而是把它们包装成某个类中的方法,并通过方法中的this对象的引用访问t_上下文)。

示例(C签名):

void my_lib_function(t_context *ctx, int some_param);

所需的C#API:

class Context
{
    // SWIG generated struct reference
    private SWIG_t_context_ptr ctx;

    public void my_lib_function(int some_param)
    {
        // call SWIG generated my_lib_function with ctx
    }
}

如果有人向我指出一个使用这种API风格的现有C(再次:不是C)库的SWIG生成的包装器,我也会很高兴;我什么也找不到。

或者,除了SWIG之外,是否还有用于C到C#用例的包装器生成器提供对API的更多控制(可能是通过公开用于代码生成的模板)?

共有1个答案

南宫凡
2023-03-14

为了解决这个问题,我创建了以下迷你头文件来演示我们(可能)真正关心的所有部分。我这样做的目标是:

  1. C#用户甚至不应该意识到这里发生了任何非OO的事情

首先,我编写了以下头文件test。h:

#ifndef TEST_H
#define TEST_H

struct context;
typedef struct context context_t;

void init_context(context_t **new);

void fini_context(context_t *new);

void context_func1(context_t *ctx, int arg1);

void context_func2(context_t *ctx, const char *arg1, double arg2);

#endif

以及相应的测试。c和一些存根实现:

#include <stdlib.h>
#include "test.h"

struct context {};
typedef struct context context_t;

void init_context(context_t **new) {
  *new = malloc(sizeof **new);
}

void fini_context(context_t *new) {
  free(new);
}

void context_func1(context_t *ctx, int arg1) {
  (void)ctx;
  (void)arg1;
}

void context_func2(context_t *ctx, const char *arg1, double arg2) {
  (void)ctx;
  (void)arg1;
  (void)arg2;
}

我们需要解决几个不同的问题,才能使其成为一个整洁、可用的OO C#接口。我会一次解决一个问题,最后给出我的首选解决方案。(对于Python,这个问题可以用一种更简单的方法来解决,但这里的解决方案将适用于Python、Java、C#以及其他可能的语言)

通常在OO风格的C API中,您会编写某种构造函数和析构函数来封装您的任何设置(可能是不透明的)。为了以明智的方式将它们呈现给目标语言,我们可以使用%扩展来编写看起来很像C构造函数/析构函数的东西,但在SWIG处理后仍然作为C出现。

%module test

%{
#include "test.h"
%}
    
%rename(Context) context; // Make it more C# like
%nodefaultctor context; // Suppress behaviour that doesn't work for opaque types
%nodefaultdtor context;
struct context {}; // context is opaque, so we need to add this to make SWIG play

%extend context {
  context() {
    context_t *tmp;
    init_context(&tmp);
    // we return context_t * from our "constructor", which becomes $self
    return tmp;
  }

  ~context() {
    // $self is the current object
    fini_context($self);
  }
}

我的设置方式允许我们使用一个可爱的把戏。当我们说:

%extend context {
  void func();
}

然后,SWIG生成一个存根,如下所示:

SWIGEXPORT void SWIGSTDCALL CSharp_Context_func(void * jarg1) {
  struct context *arg1 = (struct context *) 0 ;

  arg1 = (struct context *)jarg1; 
  context_func(arg1);
}

需要从中吸取的两件事是:

  1. 实现扩展的context::func调用的函数称为context\u func

上面的内容与我们从C端开始的内容非常吻合。因此,我们可以简单地完成以下工作:

%module test

%{
#include "test.h"
%}
    
%rename(Context) context;
%nodefaultctor context;
%nodefaultdtor context;
struct context {}; 

%extend context {
  context() {
    context_t *tmp;
    init_context(&tmp);
    return tmp;
  }

  ~context() {
    fini_context($self);
  }

  void func1(int arg1);

  void func2(const char *arg1, double arg2);
}

这并不完全符合我的目标第2点,正如我所希望的那样,您必须手动编写函数声明(除非您使用%include的技巧,并将它们保存在单个头文件中)。有了Python,您可以在导入时将所有的部分放在一起,并使其简单得多,但我看不到一种简洁的方法来枚举所有与模式匹配的函数,并将其放在SWIG生成模式的正确位置。cs文件。

这足以让我使用以下代码进行测试(使用Mono):

using System;
 
public class Run
{
    static public void Main()
    {
        Context ctx = new Context();
        ctx.func2("", 0.0);
    }
}

还有其他一些C OO风格的设计变体,使用可以解决的函数指针,还有一个类似的问题,我在过去讨论过Java。

 类似资料:
  • (假设Magic是4个字节,Command是1个字节,Options是2个字节,Bodysize是4个字节,并且body本身的长度是可变的。)我如何在不使用任何第三方库的情况下解析它? 通常我会说,可以这样做来存储数据包数据: 问题是,我首先提供头信息,然后以一种笨拙的方式添加正文数据。包对象有一个在不完整状态下可以访问的时间点。 我是用C++开发的,对于通过套接字发送和接收数据,使用了boost

  • 问题内容: 我已经看到了很多类似的问题,但是还没有找到解决我特定问题的方法。我正在尝试SWIGify一些使用std :: function的C ++ 11代码,因此可以在Java应用程序中使用它。 我遇到了这样的共享指针: 并使用shared_ptr指令成功处理了它们,如下所示: 我遇到了像这样的共享指针向量: 并使用如下模板成功处理了它们: 现在我有一个这样的方法: 而且我无法让SWIG正确包装

  • 问题 你想让你写的C代码作为一个C扩展模块来访问,想通过使用 Swig包装生成器 来完成。 解决方案 Swig通过解析C头文件并自动创建扩展代码来操作。 要使用它,你先要有一个C头文件。例如,我们示例的头文件如下: /* sample.h */ #include <math.h> extern int gcd(int, int); extern int in_mandel(double x0,

  • 面向对象编程概述 面向对象编程的两个主要特征:继承、多态 C++ 中是通过间接利用“指向父类”的指针或引用来操作其子类对象,从而达到多态的目的;如果直接操作某个实例,那么多态将无从谈起 具体来说,多态是通过动态绑定机制,达到在运行时确定实际被调用的是哪个子类类型,进而调用对应的 override 方法 Reference 《Essential C++》 第 4/5 章 - Lippman, 侯捷

  • 本文向大家介绍Js面向对象的几种方式相关面试题,主要包含被问及Js面向对象的几种方式时的应答技巧和注意事项,需要的朋友参考一下 1.对象的字面量 var obj = {} 2.创建实例对象 var obj = new Object(); 3.构造函数模式 function fn(){} , new fn(); 4.工厂模式:用一个函数,通过传递参数返回对象。function fn(params){

  • 如何使用多个类正确管理mongo连接? 例如,我有4个类管理4个集合。 收藏1。班级集合2。班级等等。。 我要做的是在每个类中创建一个connect and close方法,这会减慢应用程序中某些事务的连接 除了创建每个类的对象并分别连接每个类之外,将应用程序连接到db并开始使用所有类实例的最佳方式是什么?