SWIG C++ Python:通过引用或指针包装 int

Posted

技术标签:

【中文标题】SWIG C++ Python:通过引用或指针包装 int【英文标题】:SWIG C++ Python: wrapping int by reference or pointer 【发布时间】:2011-07-15 15:38:36 【问题描述】:

我正在尝试将一些 C++ 函数包装到 Python 包装器中。 为此,SWIG 似乎是一种不错且简单的方法。

包装有效,但在通过引用或指针传递整数时遇到问题。 由于 Python 无法使用引用,因此 SWIG 在内部将它们转换为指针。

一些简单的示例代码:

Blaat.hpp:

#ifndef __BLAAT_HPP__
#define __BLAAT_HPP
class Blaat

public:
 int mA;
 float mB;

public:
 Blaat() 
 void getA(int & fA);
 void setA(const int fA);
 ~Blaat() 
;

#endif // __BLAAT_HPP__

Blaat.cpp

#include "Blaat.hpp"
#include <iostream>

void Blaat::getA(int & fA) 
 std::cout << "[Blaat::getA] fA = " << fA << std::endl;
 fA = mA;
 

void Blaat::setA(const int fA) 
 std::cout << "[Blaat::setA] fA = " << fA << std::endl;
 mA = fA;

Blaat.i:

%module Blaat
%
/* Includes the header in the wrapper code */
#include "Blaat.hpp"
%

/* Parse the header file to generate wrappers */
%include "Blaat.hpp"

将代码转换为 Python 包装器:

#!/bin/sh
swig -python -c++ -v $1.i 
gcc -c $1_wrap.cxx -fPIC -I/usr/include/python2.6
gcc -shared $1_wrap.o -o _$1<library_path> so -L. -l$1

这一切都很好。现在,我启动 Python 并执行以下操作:

from Blaat import *
a = Blaat()
b = int(1)
a.setA(b) <-- fine, calls setA() function fine
a.getA(b) <-- does not work

在“getA()”调用时,出现以下错误:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "Blaat.py", line 86, in getA
   def getA(self, *args): return _Blaat.Blaat_getA(self, *args)
TypeError: in method 'Blaat_getA', argument 2 of type 'int &'

请注意,当通过引用和指针传递参数时,我都会遇到这个问题。 查看生成的“Blaat_wrap.cxx”文件,它停留在实际的类型转换:

res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_int,  0 );
if (!SWIG_IsOK(res2)) 
 SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Blaat_getA" "', argument " "2"" of type '" "int &""'"); 

这意味着函数 SWIG_ConvertPtr() 失败了,这很奇怪,因为它检查的类型似乎是 SWIGTYPE_p_int。 从“setA()”函数中,我们看到类型转换有效(如果按值传递)。

The SWIG documentation tells me):

支持 C++ 引用,但 SWIG 将它们转换回 指针。例如,这样的声明:

class Foo public: double bar(double &a);

有一个低级访问器

double Foo_bar(Foo *obj, double *a) obj->bar(*a);

有人可以把我丢失的东西扔进去吗?我在这一点上非常卡住...... Found this post, but this did not help either

【问题讨论】:

【参考方案1】:

我认为python没有引用返回的概念,但这里是我的解决方案:

Blaat.i:

%module Blaat
%include typemaps.i
%apply int &OUTPUT  int & fA ;
%
/* Includes the header in the wrapper code */
#include "Blaat.hpp"
%

/* Parse the header file to generate wrappers */
class Blaat

public:
 Blaat();
 void getA(int & fA);
 void setA(const int fA);
 ~Blaat();
;

b.py:

from Blaat import *
a = Blaat()
b = int(1)
a.setA(b)
b = a.getA()

跑步:

python b.py
[Blaat::setA] fA = 1
[Blaat::getA] fA = 63

【讨论】:

感谢您的回答,克里斯。确实,这是最简单的解决方案,只是按值返回。但是according to SWIG 应该可以使用引用...所以,这就是我想要的! :) 找到similar thread here。【参考方案2】:

谢谢克里斯,这行得通! 经过一番挖掘,SWIG 文档似乎并不完整。

SWIG type conversion using the typemaps.i library is described here。 我从示例中得到的是,您必须手动指定您希望将参数用作输出(这意味着关于“指针和引用”的 SWIG 文档仅适用于 INPUT 参数!)。

对于上面的简单示例,只需包含 .hpp 文件并让 SWIG 自动处理所有内容就足够了。

Blaat.i:

%module Blaat
%include typemaps.i
%apply int &OUTPUT  int & fA ;
%
#include "Blaat.hpp"
%

%include "Blaat.i"

PS:Blaat.cpp 文件 cout 错误的值,它当然应该 cout mA 而不是 fA,因为 fA 是在 cout 之后设置的......

【讨论】:

以上是关于SWIG C++ Python:通过引用或指针包装 int的主要内容,如果未能解决你的问题,请参考以下文章

使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++

SWIG C++ TCL:处理内存中预先存在的对象

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

将 python 函数传递给 SWIG 包装的 C++ 代码

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

如何在 Python + SWIG 中接收引用和指针参数?