SWIG:如何包装 std::string&(通过引用传递的 std::string)

Posted

技术标签:

【中文标题】SWIG:如何包装 std::string&(通过引用传递的 std::string)【英文标题】:SWIG: How to wrap std::string& (std::string passed by reference) 【发布时间】:2010-09-20 16:36:25 【问题描述】:

我正在使用 SWIG 从 Java 访问 C++ 代码。

公开非常量引用传递的 std::string 参数的最简单方法是什么?

感谢 typemaps.i,我将通过引用传递的原语公开为 Java 数组,而 const std::string&s 公开为 java.lang.String,感谢 std_string.i。但是非常量 std::string& 暴露为不透明指针类型SWIGTYPE_p_std__string

当前:

// C++ method                     -> // Java wrapper of C++ method
void foo( int & i )               -> public void foo( int[] i );    // OK
void bar( const std::string & s ) -> public void bar( String s );   // OK
void baz( std::string & s )       -> public void baz( SWIGTYPE_p_std__string s ); // :(

期望:

void foo( int & i )               -> public void foo( int[] i );    // OK
void bar( const std::string & s ) -> public void bar( String s );   // OK
void baz( std::string & s )       -> public void baz( String[] s ); // OK

更新:我找到了一个解决方案,如下所述。然而,这花费了比几秒钟更多的努力。我仍然有兴趣了解简单的方法。

【问题讨论】:

因为Java String 类是不可变的。因此,即使您传递了一个虚假的 String 数组,您也不能像传递引用所暗示的那样修改它。 @Martin York - 字符串对象是不可变的。但是,String 数组的成员是对 String 对象的可变引用。 @Andy Thomas-Cramer:但这与通过引用传递不同。您正在传递一个可以操作的对象。但是对于字符串数组,对象仍然是不可更改的。除非您建议被调用的函数可以通过替换来更改字符串!这将需要 Glue 代码获取返回的 Java String 对象并将其放入传递的 C++ 字符串对象中。 @Martin York - 我来包装传递引用,而不是实现它。目标是发送和接收数据。原始类型的解决方法是在函数进入之前和函数退出之后转换数组成员。我用 String[] 为 std::string& 寻求同样的方法。在 Java 中,String[] 包含对 String 对象的引用——指针。本机胶水代码可以很容易地用一个对 Java 字符串的新引用替换单例数组成员,该 Java 字符串是从它通过引用传递的本地 std::string 转换而来的。我知道原始的 Java String 对象没有被修改,但我不需要。 @Andy Thomas-Cramer:我明白你在做什么。但问题是 int/String 在 Java 中是根本不同的。请注意,int 是未装箱的,而不是对象。 【参考方案1】:

我能找到的最佳方法是编写自己的类型图。我一直希望有一些琐碎的 SWIG 指令。

如果其他人需要这个,我就是这样做的。请记住,我不是 SWIG 专家。

首先,您需要定义一些类型映射以应用于 std::string& 参数。您只需定义一次。 (注意:在某些配置中可能需要额外的类型映射。)

%typemap(jni) std::string *INOUT, std::string &INOUT %jobjectArray%
%typemap(jtype) std::string *INOUT, std::string &INOUT "java.lang.String[]"
%typemap(jstype) std::string *INOUT, std::string &INOUT "java.lang.String[]"
%typemap(javain) std::string *INOUT, std::string &INOUT "$javainput"

%typemap(in) std::string *INOUT (std::string strTemp ), std::string &INOUT (std::string strTemp ) 
  if (!$input) 
    SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
    return $null;
  
  if (JCALL1(GetArrayLength, jenv, $input) == 0) 
    SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
    return $null;
  

  jobject oInput = JCALL2(GetObjectArrayElement, jenv, $input, 0); 
  if ( NULL != oInput ) 
    jstring sInput = static_cast<jstring>( oInput );

    const char * $1_pstr = (const char *)jenv->GetStringUTFChars(sInput, 0); 
    if (!$1_pstr) return $null;
    strTemp.assign( $1_pstr );
    jenv->ReleaseStringUTFChars( sInput, $1_pstr);  
  

  $1 = &strTemp;


%typemap(freearg) std::string *INOUT, std::string &INOUT ""

%typemap(argout) std::string *INOUT, std::string &INOUT
 
  jstring jStrTemp = jenv->NewStringUTF( strTemp$argnum.c_str() );
  JCALL3(SetObjectArrayElement, jenv, $input, 0, jStrTemp ); 

接下来,对于每个这样的C++参数模式...

void foo( std::string & xyzzy );
void bar( std::string & xyzzy );
void baz( ..., std::string & xyzzy, ... );

...您使用此 SWIG 指令应用上面的类型映射:

%apply std::string &INOUT  std::string & xyzzy ;

生成的绑定如下所示:

public void foo( java.lang.String[] xyzzy );
public void bar( java.lang.String[] xyzzy );
public void baz( ..., java.lang.String[] xyzzy, ... );

它们每个都需要一个单元素字符串数组。进入时,第一个元素可能为空。如果非空,则将其转换为 UTF-8 std::string 值并传递给 C++ 函数。退出时,通过引用传递的 std::string 的值从 UTF-8 转换回 Java 字符串。

【讨论】:

从他死后回来 - 我想我在这里问同样的问题:***.com/questions/4652638/… - 你能指点我一些起始文件吗?你在哪里定义类型映射?你如何让 SWIG 使用它?我试图把它放在 typemaps.i 和 %include 到我的模块文件中,我的输出看起来完全一样 我认为您应该将INPUT 更改为OUTPUT,因为c++ 代码将string 作为输出返回。检查这篇文章:***.com/a/11967859/365229 @raypixar - 您是否可能将上面的INOUT 误读为“INPUT”? INOUT 参数可用作输入和输出。一般来说,像void baz( std::string &amp; s ) 这样的函数可能会使用参数进行输入和/或输出。在swig.org/Doc2.0/SWIGDocumentation.html#Arguments_nn6 上查看有关 INOUT 的更多详细信息 @AndyThomas OMG!我瞎了!

以上是关于SWIG:如何包装 std::string&(通过引用传递的 std::string)的主要内容,如果未能解决你的问题,请参考以下文章

swig 对基类“std::string”一无所知,被忽略

C# SWIG 向量<字符串> 到字符串 []

使用 SWIG,如何将 C++ void func(Class& out) 包装为 C# Class func()?

[swig-JavaScript] 是不是支持 std::vector<std::string>* 作为输出?

如何使用 SWIG 在 Python 中将 operator<< 包装到 __str__?

SWIG 不接受指针参数的包装对象