【问题标题】:Passing python StringIO to C++ stringstream using swig使用 swig 将 python StringIO 传递给 C++ stringstream
【发布时间】:2012-02-16 23:01:55
【问题描述】:

我有一些生成 StringIO 变量的 python 代码。我想使用 stringstream 参数将此变量传递给 C++ 函数(假设 C++ stringstream 是与 python StringIO 最接近的匹配项)。有没有一种使用 swig 进行翻译的简单方法?

我在 swig 模块中看到一个 std_sstream.i,其中包含一些 stringstream 代码,但我在 swig 文档中找不到对它的任何引用,或者在网络搜索中使用它的任何示例。

为了让它更清晰一点,我将在下面包含一些非常简单的代码。 这是 test.cpp,它是固定的,我无法更改:

#include <iostream>
#include <sstream>

#include "test.h"

using namespace std;

void StTest(stringstream &ss)
{
    cout << ss << endl;
}

这里的 test.h 也是固定的:

#include <sstream>

using namespace std;

void StTest(stringstream &ss);

这是我可以编辑并调用 C++ StTest 函数的 python 代码(我们称之为 test_test.py):

#!/usr/bin/env python

import StringIO
import test

ss = StringIO.StringIO()
ss.write("Hello")

# Maybe some thing here to convert ss from StringIO to stringstream

test.StTest(ss)

所以我在上面的注释行中寻找可以从 StringIO 转换为 stringstream 的东西。

这是我对 swig 的 test.i 文件的初步挖掘:

/* test.i */
%module test

%{
#include "test.h"
%}

%include "std_sstream.i"
%include "test.h"

我在 test.i 中包含了“std_sstream.i”,因为这是应该使用的,我想。我需要在这个文件中添加一些东西来让它做一些事情吗?

目前运行test_test.py的报错是:

TypeError: in method 'StTest', argument 1 of type 'stringstream &'

【问题讨论】:

    标签: c++ python swig stringstream stringio


    【解决方案1】:

    为什么不直接用一个字符串调用 PyArg_ParseTuple,你可以通过调用 StringIO.getvalue()?

    有这样的东西?

    const char* cstring;
    if (!PyArg_ParseTuple(args,"s", &cstring)) //Note the &
            return NULL;
    std::string stdstring = cstring;
    std::stringstream buffer(stdstring);
    

    另请参阅 cStringIO here 的 C API。

    在附加要求之后,我尝试在固定约束内使用 SWIG 找到解决方案。

    第一个可能的解决方案是内联或扩展解决方案(扩展 StTest 以获取一个字符串,然后让扩展创建一个字符串流并调用 StTest),但由于提供的示例只有一个方法并且没有类,所以这没有满足约束。

    最终的接口文件如下所示。

    /* test.i */
    %module test
    
    %{
    #include "test.h"
    #include <sstream>
    #include <iostream>
    %}
    using namespace std;
    %include "std_sstream.i"
    %include "test.h"
    
    %include <typemaps.i>
    
    %typemap(in) std::stringstream & (char *buf = 0, size_t size = 0, int alloc = 0, std::stringstream stream)
    {
      if (SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc) != SWIG_OK)
      {
        %argument_fail(SWIG_TypeError, "(TYPEMAP, SIZE)", $symname, $argnum);
      }
    
      stream.write(buf, size - 1);
    
      $1 = &stream;
    }
    

    请注意,SWIG 忽略了上面接口文件中的类型映射,不知道为什么。它设法在 Python 中创建 stringstream 对象,但它们不会传递给您的 StTest,给出相同的类型错误,因为对象的类型不是 stringstream & 的类型(也映射的 swig 类型没有匹配 std_sstream.i 生成的类型,可能是因为它不包含引用类型映射)。

    接下来是我建议覆盖 SWIG 包装器的方法的实现,生成的包装函数如下所示。 (不包括整个包装文件,因为它超过 18000 行)

    SWIGINTERN PyObject *_wrap_StTest(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
      PyObject *resultobj = 0;
      void *argp1 = 0 ;
      int res1 = 0 ;
      PyObject * obj0 = 0 ;
      int argc;
      PyObject *argv[3];
      int ii;
      char *cstring;
      std::stringstream testbuffer;
      if (!PyTuple_Check(args)) SWIG_fail;
      argc = args ? (int)PyObject_Length(args) : 0;
      for (ii = 0; (ii < 2) && (ii < argc); ii++) {
        argv[ii] = PyTuple_GET_ITEM(args,ii);
      }
      if (argc == 1) {
    
      if (!PyArg_ParseTuple(args,"s",&cstring)) 
    SWIG_fail;
      std::string teststring = cstring;
      testbuffer.str(cstring);
      std::cout << "the string in the stream: " << testbuffer.str() << std::endl;
      }  
    
      StTest(testbuffer);
      resultobj = SWIG_Py_Void();
      return resultobj;
    fail:
      return NULL;
    }   
    

    流线中的字符串打印正确,但是将字符串流传递给 StTest 函数会打印字符串流在内存中的位置。这是意料之中的,因为字符串流没有像以下Stack Overflow Question 的接受答案那样绑定。

    我假设StTest(testbuffer); 可以替换为使用 boost 绑定的版本,它可以按要求工作,但已经能够验证。

    包括有帮助的参考资料

    【讨论】:

    • 我真的不能用 C++ 代码做很多事情,我可以编辑 python 代码来完成这项工作,所以我认为这个建议不适合我所追求的。跨度>
    • 我刚刚在我的原始问题中添加了一些示例代码以使其更清晰。
    猜你喜欢
    • 2021-11-03
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    • 2016-09-15
    相关资源
    最近更新 更多