当前位置: 首页 > 面试题库 >

修改SWIG接口文件以支持C void *和结构返回类型

邬阳
2023-03-14
问题内容

我正在使用SWIG为大量的C API生成我的JNI层,我想知道以下情况的最佳实践是什么。以下内容不仅适用于SWIG,而且适用于一般JNI。

当C函数返回指向Structures的指针时,应该大量使用SWIG接口文件(JNI逻辑)还是应该创建C包装函数以分段返回数据(即,包含各种数据元素的char数组)?当C函数返回void *时,是否应该修改C API以返回实际的数据类型,无论是原始类型还是结构类型?我不确定是否要添加大量逻辑并创建中间层(SWIG接口文件/ JNI逻辑)。有什么想法吗?


问题答案:

过去,我的处理方法是编写尽可能少的代码以使其工作。当我必须编写代码以使其工作时,请按以下优先顺序进行编写:

  1. 在原始库中以C或C 编写-每个人都可以使用此代码,而不必编写任何特定于Java或SWIG的东西(例如,在C 添加更多重载,在C中添加更多版本的函数,使用SWIG知道的返回类型关于他们)

  2. 写更多的目标语言-提供“胶水”以将库的某些部分放在一起。在这种情况下,它将是Java。

完全是SWIG之外的“纯” Java,还是作为SWIG接口文件的一部分,从我的角度来看,这并不重要。Java界面的用户应该无法区分两者。但是,在许多情况下,您都可以使用SWIG来避免重复。

  1. 通过SWIG类型图编写一些JNI。这很丑陋,如果您不熟悉它,容易出错,难以维护(可以说),并且仅对SWIG + Java有用。使用SWIG类型映射至少确实意味着您为每种包装类型只编写一次。

我将这个时间胜过2的次数是以下一项或多项:

  1. 大量出现时(节省重复编码)
  2. 我根本不了解目标语言,在这种情况下,使用该语言的C API可能比用该语言编写东西要容易
  3. 用户会期望的
  4. 否则就无法使用以前的样式。
    基本上,我建议的这些准则是尝试将功能交付给尽可能多的库用户,同时最大程度地减少您必须编写的额外的,目标语言特定的代码,并减少必须编写时的复杂性。

对于以下特定情况sockaddr_in*

方法1

我要尝试做的第一件事是避免包装除指向它的指针之外的任何东西。这是swig在默认情况下所做的SWIGTYPE_p_sockaddr_in事情。如果您所要做的只是将它从一件事传递到另一件事,以容器的形式存储/作为成员等,则可以很高兴地在Java中使用这种“未知”类型。

public static void main(String[] argv) {
  Module.takes_a_sockaddr(Module.returns_a_sockaddr());
}

如果这样做不能解决问题,则可以使用C编写另一个函数,例如:

const char * sockaddr2host(struct sockaddr_in *in); // Some code to get the host as a string
unsigned short sockaddr2port(struct sockaddr_in *in); // Some code to get the port

不过,在这种情况下,这不是很好-使用地址族(您可能会避免使用sockaddr_in)来处理地址族(这就是您为什么要首先使用它的原因)有一定的复杂性,但这并不是特定于Java的,它并不是晦涩的语法,除此之外,这一切都会自动为您完成。

方法2

如果那还不够好,那么我将开始考虑编写一些Java-您可以通过将SWIGTYPE_p_sockaddr_in类型隐藏为自己的Java类型的私有成员,并包装对函数的调用来公开一个更好的接口在某种为您构造类型的Java中返回它,例如

public class MyExtension {
  private MyExtension() { }
  private SWIGTYPE_p_sockaddr_in detail;
  public static MyExtension native_call() {
    MyExtension e = new MyExtension();
    e.detail = Module.real_native_call();
    return e;
  }

  public void some_call_that_takes_a_sockaddr() {
    Module.real_call(detail);
  }
}

无需编写额外的SWIG,无需编写JNI。您可以通过使用SWIG来做到这一点,%pragma(modulecode)以使其在SWIG实际生成的模块上全部重载-对于Java用户来说,这似乎更自然(这看起来并不特殊),并且实际上也没有任何复杂之处。SWIG仍然在努力,这只是为了避免在Java端重复编码而提供了一些技巧。

方法3

这基本上是我先前回答的第二部分。很好,因为它看起来和感觉都是Java用户所固有的,并且C库也不必修改。本质上,类型映射提供了一种干净的语法,用于封装JNI调用,以将Java用户期望的内容转换为C的工作方式,并且双方都不了解对方的前景。

缺点是,它较难维护且确实很难调试。我的经验是,SWIG在类似这样的事情上有一个陡峭的学习曲线,但是一旦达到一个点,编写类型图就不需要花费太多精力,像这样,它们就可以通过重用和封装C而为您提供强大的功能type-> Java类型映射非常有用且功能强大。

如果您是团队中的一员,但只有一个真正了解SWIG界面的人,那么这就提出了一个很大的“如果您被公交车撞到怎么办?” 影响整个项目。(不过,这可能会让您不愉快!)



 类似资料:
  • 问题内容: 这是我前一段时间问过的问题的延续。为通过参数返回的函数创建类型图 在上一个问题中,接口文件如下: 现在,我必须解析位于structs.h中的gaiaTextReaderPtr结构。该结构位于以下代码的底部,尽管我也包括了其中的其他结构以提供完整的图片。 我用创建的SWIG不透明数据类型下划线 任何帮助将不胜感激解决!关于汉克 第二部分 1: 一位开发人员曾这样说过toUtf8无效: 嗨

  • 我们解决什么问题 我们知道,JDK中的Cloneable接口只是一个空接口,并没有定义成员,它存在的意义仅仅是指明一个类的实例化对象支持位复制(就是对象克隆),如果不实现这个类,调用对象的clone()方法就会抛出CloneNotSupportedException异常。而且,因为clone()方法在Object对象中,返回值也是Object对象,因此克隆后我们需要自己强转下类型。 泛型克隆接口

  • 直接使用浏览器提供的API对DOM结构进行修改,不但代码复杂,而且要针对浏览器写不同的代码。 有了jQuery,我们就专注于操作jQuery对象本身,底层的DOM操作由jQuery完成就可以了,这样一来,修改DOM也大大简化了。 添加DOM 要添加新的DOM节点,除了通过jQuery的html()这种暴力方法外,还可以用append()方法,例如: <div id="test-div">

  • 在那里,我被告知接口和抽象类除了方法签名(名称、参数)和返回类型之外没有实现/方法体,所以通常我们写: 然而,我想知道我们能不能这样写: 因为它表明,当我们创建接口或抽象类时,返回类型可以在方法中

  • 我写了自己的类加载器,它与类一起工作,实现了接口插件。但是我不能将类转换为插件。怎么了? 错误:(18,47)java:不兼容的类型:java。lang.类无法转换为插件 我补充说,这是我的SimpleClassLoader类的主要部分,它扩展了ClassLoader。

  • 我已经成功地从一个。yaml打开api描述符文件,但正如问题标题中所述,我希望将这些接口的响应类型从ResponseEntity更改为我自己的类型。基本上,接口没有此签名: 对于基本上以这种方式实现的方法: 我希望生成的接口尽可能简单 同样的事情,我自己定义的类,而不是