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

发布于 2024-11-24 03:16:12 字数 2532 浏览 0 评论 0原文

我正在尝试将一些 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()”函数中,我们看到类型转换有效(如果按值传递)。

SWIG 文档告诉我):

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

class Foo { public: 双栏(double &a); }

有一个低级访问器

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

有人可以把我丢失的东西扔进去吗 我现在很困惑...... 找到这篇文章,但这也没有帮助

I'm trying to wrap some C++ functions into a Python wrapper.
For this, it seems SWIG is a nice and easy way.

Wrapping works, but I get a problem when passing integers by reference or by pointer.
Since Python cannot work with references, SWIG internally converts these to pointers.

Some simple example code:

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"

Than convert the code into a Python wrapper:

#!/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

This all works fine. Now, I start Python and do:

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

At the "getA()" call, the following error occurs:

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 &'

Note that I get this problem both when passing the argument by reference and by pointer.
Looking at the generated "Blaat_wrap.cxx" file, it stops at the actual type conversion:

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 &""'"); 
}

This means that the function SWIG_ConvertPtr() fails, which is strange because it seems that the type it checks for is SWIGTYPE_p_int.
From the "setA()" function, we see that the type conversion works (if passing by value).

The SWIG documentation tells me):

C++ references are supported, but SWIG transforms them back into
pointers. For example, a declaration like this :

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

has a low-level accessor

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

Can someone throw in the thing I'm missing? I'm quite stuck at this point...
Found this post, but this did not help either

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

混吃等死 2024-12-01 03:16:12

我不认为 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()

Running:

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

I don't think python has the concept of return by reference, but here is my solution:

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()

Running:

python b.py
[Blaat::setA] fA = 1
[Blaat::getA] fA = 63
流年里的时光 2024-12-01 03:16:12

谢谢克里斯,这有效!
经过更多挖掘后,SWIG 文档似乎并不完整。

使用 typemaps.i 库的 SWIG 类型转换描述如下
我从示例中得到的是,您必须手动指定您希望将参数用作输出(这意味着有关“指针和引用”的 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 文件计算出错误的值,它当然应该计算 mA 而不是 fA,因为 fA 是在 cout 之后设置的...

Thanks Chris, this works!
After a bit of more digging, it seems that the SWIG documentation is not complete.

SWIG type conversion using the typemaps.i library is described here.
What I get from the example is that you HAVE to manually specify that you want an argument to be used as output (which means that the SWIG documentation on 'pointers and references' only holds for INPUT arguments only!).

For the simple example above, it is sufficient to just including the .hpp file and let SWIG handle everything automatically.

Blaat.i:

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

%include "Blaat.i"

PS: The Blaat.cpp file couts the wrong value, it should of course cout mA instead of fA since fA is set after the cout...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文