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

SWIG(v1.3.29)生成了C ++到Java Vector类,无法正常运行

淳于泓
2023-03-14
问题内容

我有一些本机C ++代码,正在使用SWIG转换为Java,以便我的Java应用程序可以使用它。特别是有些函数返回std ::
vector。这是我的界面文件的一个片段:

%include "std_vector.i"
namespace std {
  %template(Vector) vector<double>;
  %template(Matrix) vector<vector<double> >;
}

%include "std_string.i"

std_string.istd_vector.i包含在我正在使用的SWIG版本中。我的第一个惊喜是Java输出包含SWIG的Vector类的“自有”版本(与using相对java.util.Vector)。我的真正问题是从这些函数返回的Vector似乎不起作用。例如,我无法使用get()(有时会使程序崩溃)或size()返回负值的函数来检索其内容。我知道Vectors包含数据,因为我编码了相同功能的“字符串”版本,这些功能只是简单地遍历Vectors(返回本机C
++代码)并以逗号分隔的String值返回内容。尽管这是一个有效的解决方法,但最终我希望它能够与我一起使用并能够接收和操作Vectors。任何帮助/提示将不胜感激。


问题答案:

std::vectorJava中自动换行的基本类型为java.util.AbstractList。使用java.util.Vector,因为你有两套存储,一个在最终的基地将是奇数std::vector,还有一个在java.util.Vector

但是,SWIG不为您执行此操作的原因是因为您AbstractList<double>在Java中无法做到这一点,它必须是AbstractList<Double>Double继承自Objectwhile
double是原始类型)。

说了这么多我已经把一个小例子,它包装std::vector<double>并`std::vector<std::vector

很好地在Java中。它还不完整,但是它支持Java和set()/get()`on元素中的“ for
each”迭代样式。足以说明如何/在需要时实施其他事情。

我将逐步介绍接口文件,但基本上,它们将是连续且完整的。

与开始num.i定义我们的模块num

%module num

%{
#include <vector>
#include <stdexcept>

std::vector<double> testVec() {
  return std::vector<double>(10,1.0);
}

std::vector<std::vector<double> > testMat() {
  return std::vector<std::vector<double> >(10, testVec());
}
%}

%pragma(java) jniclasscode=%{
  static {
    try {
        System.loadLibrary("num");
    } catch (UnsatisfiedLinkError e) {
      System.err.println("Native code library failed to load. \n" + e);
      System.exit(1);
    }
  }
%}

我们有#include用于生成的s
num_wrap.cxx和两个用于测试的函数的实现(它们可能在单独的文件中,出于懒惰/方便的考虑,我将其放在此处)。

%pragma(java) jniclasscode=我喜欢在Java SWIG接口中使用一个技巧,以使接口的用户透明地加载共享库/ DLL。

接口文件中的下一部分是std::vector我们要包装的部分。我没有使用,std_vector.i因为我们需要进行一些更改:

namespace std {

    template<class T> class vector {
      public:
        typedef size_t size_type;
        typedef T value_type;
        typedef const value_type& const_reference;
        %rename(size_impl) size;
        vector();
        vector(size_type n);
        size_type size() const;
        size_type capacity() const;
        void reserve(size_type n);
        %rename(isEmpty) empty;
        bool empty() const;
        void clear();
        void push_back(const value_type& x);
        %extend {
            const_reference get_impl(int i) throw (std::out_of_range) {
                // at will throw if needed, swig will handle
                return self->at(i);
            }
            void set_impl(int i, const value_type& val) throw (std::out_of_range) {
                // at can throw
                self->at(i) = val;
            }
        }
    };
}

这里是主要的变化%rename(size_impl) size;,它告诉SWIG暴露size()std::vector作为size_impl代替。我们需要这样做,因为Java期望size返回一个int地方,因为std::vector版本返回的地方size_type很可能不会返回int

接下来在接口文件中,我们告诉我们要实现什么基类和接口,以及编写一些额外的Java代码以强制具有不兼容类型的函数之间的工作:

%typemap(javabase) std::vector<double> "java.util.AbstractList<Double>"
%typemap(javainterface) std::vector<double> "java.util.RandomAccess"
%typemap(javacode) std::vector<double> %{
  public Double get(int idx) {
    return get_impl(idx);
  }
  public int size() {
    return (int)size_impl();
  }
  public Double set(int idx, Double d) {
    Double old = get_impl(idx);
    set_impl(idx, d.doubleValue());
    return old;
  }

%}

%typemap(javabase) std::vector<std::vector<double> > "java.util.AbstractList<Vector>"
%typemap(javainterface) std::vector<std::vector<double> > "java.util.RandomAccess"
%typemap(javacode) std::vector<std::vector<double> > %{
  public Vector get(int idx) {
    return get_impl(idx);
  }
  public int size() {
    return (int)size_impl();
  }
  public Vector set(int idx, Vector v) {
    Vector old = get_impl(idx);
    set_impl(idx, v);
    return old;
  }

%}

这设置了java.util.AbstractList<Double>for
std::vector<double>java.util.AbstractList<Vector>for
的基类`std::vector<std::vector

(这Vector是我们将std::vector `在接口的Java端调用的基类)。

我们还在Java方面提供get和的实现set,可以处理doubleDouble转换并再次返回。

最后,在界面中添加:

namespace std {
  %template(Vector) std::vector<double>;
  %template(Matrix) std::vector<vector<double> >;
}

std::vector<double> testVec();
std::vector<std::vector<double> > testMat();

这告诉SWIG指std::vector<double>(与特定类型),其Vector同样地,对于`std::vector<vector

Matrix`。我们还告诉SWIG公开我们的两个测试功能。

接下来test.java,,这main是Java中的一个简单示例,它可以稍微练习一下我们的代码:

import java.util.AbstractList;

public class test {
  public static void main(String[] argv) {
    Vector v = num.testVec();
    AbstractList<Double> l = v;
    for (Double d: l) {
      System.out.println(d);
    }
    Matrix m = num.testMat();
    m.get(5).set(5, new Double(5.0));
    for (Vector col: m) {
      for (Double d: col) {
        System.out.print(d + " ");
      }
      System.out.println();
    }
  }
}

要构建并运行它,我们要做:

swig -java -c++ num.i
g++ -Wall -Wextra num_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libnum.so

javac test.java && LD_LIBRARY_PATH=. java test

我在Linux / x86上使用g ++版本4.4和SWIG 1.3.40对此进行了测试

的完整版本num.i可以在此处找到,但始终可以通过将每个部分粘贴到一个文件中来从此答案中重建。

我尚未实现的事情AbstractList

  1. add()-可以通过push_back(),std_vector.i来实现,默认情况下甚至尝试实现兼容的东西,但是它不适用于Doublevs double问题或与AbstractList(不要忘记增加modCount)中指定的返回类型匹配
  2. remove()- std::vector就时间复杂度而言不是很好,但也不是不可能实现(同样使用modCount
  3. Collection建议使用另一个构造函数,但此处未实现。可以在同一个地方执行set()get()是的,但需要$javaclassname正确地命名生成的构造函数。
  4. 您可能想使用类似这样的方法来检查size_type-> int转换size()是否正确。


 类似资料:
  • 我使用ApacheStorm与Apache Kafka。使用的喷口是Kafka喷口,但它没有阅读Kafka主题的任何内容。我不知道这是否与我在暴风的工人中面临的问题有关。如果您知道任何相关解决方案,请告知我。 Storm拓扑已成功上载到Storm。我获取了日志,下面是工作人员在其文件:

  • 我正在使用SWIG生成一个围绕freetype的C包装。我的目标是为WinRT生成一个带有C接口的freetype DLL,该接口将在Windows Phone 8上运行,然而,生成的C包装似乎依赖于Tcl。由于我不需要Tcl绑定,而且WinRT默认情况下不提供Tcl,我想知道是否可以以某种方式关闭Tcl依赖项。我正在使用Visual Studio 2012编译生成的代码。 我查阅了文档,只找到了

  • 我目前在编译protobuf生成的C代码时遇到了一些问题<代码>协议(code>protoc)运行正常,不会显示任何警告,但是,当我尝试编译生成的C代码以便构建静态库时,g向我显示以下消息: CanInfo。pb。抄送:107:5:错误:“::protobuf\u BusType\u 2eproto”尚未声明107;::protobuf\u BusType\u 2eproto::AddDescri

  • 问题内容: 以下子组件从其父组件接收道具。然后,使用将道具设置为自己的状态,并使用将值渲染到相应的输入字段。 我用来在子组件收到新道具时更新其状态。 最初,调用该组件时,它可以正常工作。问题是第二次通过道具时发生的,触发道具通过的相应按钮需要两次单击才能设置孩子的状态。 我可能使用不正确? 完整代码: 问题答案: 我可能会错误地使用componentWillRecieveProps? 是的,因为您

  • Gradle版本:5.1 Java版本:11 我在gradle文件中定义了以下任务来生成QueryDSL类: 下面是我的依赖项块: 如果我执行'gradlew generateQClasses,我会在日志中看到以下内容: 它失败,错误是文件已经存在。如何配置此任务以覆盖文件(如果存在)? 此外,上面的配置是根项目的配置,它有5个子项目。能够覆盖其中一个子项目中的文件,但不能覆盖其他子项目中的文件(