SWIG,Python,C,带有void返回参数

时间:2012-07-10 22:27:01

标签: python c swig void-pointers

我在C头文件中有以下函数构造函数:

int my_fun(int i, void *a, void *b, void *c);

为了提供一些上下文,我提供了一个C代码实现,说明了如何使用它:

int error;
double *a, *b, *c;

int i = 1;
int num = 500;
int num_dim = 2;

a = (double *) calloc(num, sizeof(double));
b = (double *) calloc(num, sizeof(double));
if (num_dim >= 3)
   c = (double *) calloc(num, sizeof(double));
else
   c = 0

 error = my_fun(i,a,b,c);
 error = my_fun(i,NULL,b,NULL); /*read only b*/

我想知道如何在SWIG接口文件中实现它。我已将typemaps.i用于其他类型的指针返回参数,但它似乎不支持void*

1 个答案:

答案 0 :(得分:3)

SWIG提供了一个与calloc匹配良好的文件carrays.i。您可以使用宏%array_functions%array_class来公开将C样式数组包装到目标语言的一些辅助函数。 (即使你使用的是C,你仍然可以使用它们)。我创建了以下界面,用my_fun包装并定义一个简单的%include

%module test

%include "carrays.i"

%array_functions(double,DoubleArray)

%inline %{
  int my_fun(int i, void *a, void *b, void *c) {
    printf("my_fun: i=%d, a=%p, b=%p, c=%p\n",i,a,b,c);
    return 0;
  }
%}

如果您想支持的种类不仅仅是calloc(num, sizeof(double)),那么您需要在界面文件中添加更多%array_functions。 carrays.i还生成用于获取和设置数组中特定值以及删除它们的函数

之后,您的示例用法在Python中变为以下内容:

import test

i = 5
num = 500
num_dim = 2

a = test.new_DoubleArray(num)
b = test.new_DoubleArray(num)
c = None
if num_dim >= 3:
  c =  test.new_DoubleArray(num)

error = test.my_fun(i,a,b,c)
error = test.my_fun(i,None,b,None)

# Beware of the exceptions, you need a finally: really
test.delete_DoubleArray(a)
test.delete_DoubleArray(b)
test.delete_DoubleArray(c)

我在我的系统上编译并运行了这个:

swig -python -Wall test.i 
gcc -fPIC -I/usr/include/python2.7 test_wrap.c -shared -o _test.so -Wall -Wextra
LD_LIBRARY_PATH=. python2.7 run.py

其中给出了以下输出:

my_fun: i=5, a=0x2767fa0, b=0x2768f50, c=(nil)
my_fun: i=5, a=(nil), b=0x2768f50, c=(nil)

由于此处的“数组”只是C中使用calloc分配的实际内存块的代理,因此下次读取时,您可以从Python中看到对数组所做的任何更改。


如果使用%array_class代替%array_functions,Python代码将变为:

import test

i = 5
num = 500
num_dim = 2

a = test.DoubleArray(num)
b = test.DoubleArray(num)
c = None
if num_dim >= 3:
  c =  test.DoubleArray(num)

error = test.my_fun(i,a.cast(),b.cast(),c.cast() if c else None)
error = test.my_fun(i,None,b.cast(),None)

请注意,此处引用计数已消除了显式删除数组的需要,通过推迟引用计数来解决异常问题。 %array_class还提供了__getitem____setitem__的实现,因此它可以像Python中的任何其他数组或容器一样进行子脚本编写。 (尽管没有界限检查,就像C)