SWIG:如何 return 使用 %apply 的结构? 'No typemaps defined' 警告
SWIG: How to return a struct using %apply? 'No typemaps defined' warning
我目前有一个函数使用结构体作为 return 一些信息的缓冲区,例如:
int example_reader(int code, void* return_struct);
我的目标是当我使用 SWIG 包装这个函数以便它可以在 Python 中使用时,我将 return 结构和函数的常规 [=26] =] 值。到目前为止,我一直在使用 %apply 命令这样做:
%apply struct ret_struct *OUTPUT {void* return_struct};
但是,当我将以上行添加到我的 .i 文件并尝试 运行 SWIG 时,我收到以下警告:
"warning 453: Can't apply (struct ret_struct *OUTPUT. No typemaps are defined"
我相信我包含了 .h 文件,它定义了我正在尝试 return 的结构,所以我无法查明问题所在。如果问题似乎涉及结构的不当包含,请纠正我。我已经尝试通读 SWIG 文档以及其他 Stack Overflow 帖子,以了解问题可能出在哪里,但到目前为止我还没有弄清楚。这个问题变得有点棘手,因为我试图 return 一个指向结构的空指针,而我试图包装的代码可能有多种结构供我使用 return。处理此结构的 return 的明智方法是什么?谢谢!
我在这里给出了一个完整的 C 示例,其中一个接口用于 return 将结构与 return 值一起连接到目标语言。通过这种方式,您可以创建一个适当的接口,其中 header 中没有给出实现。那不是虚拟析构函数的默认实现。如果不想使用接口,可以让 SWIG 和 Python 了解数据的表示方式。
接口header:foo.h
typedef struct _Foo Foo;
int foo_new(Foo **obj);
int foo_free(Foo *obj);
int foo_get_value_a(Foo *obj, int *result);
int foo_set_value_a(Foo *obj, int value);
int foo_get_value_b(Foo *obj, char **result);
int foo_set_value_b(Foo *obj, char *value);
SWIG 接口:foo.i
%module foo
%{
#include "foo.h"
%}
%include "typemaps.i"
%typemap(in, numinputs=0) Foo ** (Foo *temp) {
= &temp;
}
%typemap(argout) Foo ** {
PyObject* temp = NULL;
if (!PyList_Check($result)) {
temp = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, temp);
}
temp = SWIG_NewPointerObj(*, SWIGTYPE_p__Foo, SWIG_POINTER_NEW);
PyList_Append($result, temp);
Py_DECREF(temp);
}
%delobject foo_free; // Protect for double deletion
struct _Foo {};
%extend _Foo {
~_Foo() {
foo_free($self);
}
};
%ignore _Foo;
接口的一些实现:foo.c
%include "foo.h"
#include "foo.h"
#include "stdlib.h"
#include "string.h"
struct FooImpl {
char* c;
int i;
};
int foo_new(Foo **obj)
{
struct FooImpl* f = (struct FooImpl*) malloc(sizeof(struct FooImpl));
f->c = NULL;
*obj = (Foo*) f;
return 0;
}
int foo_free(Foo *obj)
{
struct FooImpl* impl = (struct FooImpl*) obj;
if (impl) {
if (impl->c) {
free(impl->c);
impl->c = NULL;
}
}
return 0;
}
int foo_get_value_a(Foo *obj, int *result)
{
struct FooImpl* impl = (struct FooImpl*) obj;
*result = impl->i;
return 0;
}
int foo_set_value_a(Foo *obj, int value)
{
struct FooImpl* impl = (struct FooImpl*) obj;
impl->i = value;
return 0;
}
int foo_get_value_b(Foo *obj, char **result)
{
struct FooImpl* impl = (struct FooImpl*) obj;
*result = impl->c;
return 0;
}
int foo_set_value_b(Foo *obj, char *value)
{
struct FooImpl* impl = (struct FooImpl*) obj;
int len = strlen(value);
if (impl->c) {
free(impl->c);
}
impl->c = (char*)malloc(len+1);
strcpy(impl->c,value);
return 0;
}
构建脚本
#!/usr/bin/env python
from distutils.core import setup, Extension
import os
os.environ['CC'] = 'gcc';
setup(name='foo',
version='1.0',
ext_modules =[Extension('_foo',
['foo.i','foo.c'])])
用法:
import foo
OK, f = foo.foo_new()
OK = foo.foo_set_value_b(f, 'Hello world!')
OK = foo.foo_free(f)
OK, f = foo.foo_new()
# Test safe to double delete
del f
我目前有一个函数使用结构体作为 return 一些信息的缓冲区,例如:
int example_reader(int code, void* return_struct);
我的目标是当我使用 SWIG 包装这个函数以便它可以在 Python 中使用时,我将 return 结构和函数的常规 [=26] =] 值。到目前为止,我一直在使用 %apply 命令这样做:
%apply struct ret_struct *OUTPUT {void* return_struct};
但是,当我将以上行添加到我的 .i 文件并尝试 运行 SWIG 时,我收到以下警告:
"warning 453: Can't apply (struct ret_struct *OUTPUT. No typemaps are defined"
我相信我包含了 .h 文件,它定义了我正在尝试 return 的结构,所以我无法查明问题所在。如果问题似乎涉及结构的不当包含,请纠正我。我已经尝试通读 SWIG 文档以及其他 Stack Overflow 帖子,以了解问题可能出在哪里,但到目前为止我还没有弄清楚。这个问题变得有点棘手,因为我试图 return 一个指向结构的空指针,而我试图包装的代码可能有多种结构供我使用 return。处理此结构的 return 的明智方法是什么?谢谢!
我在这里给出了一个完整的 C 示例,其中一个接口用于 return 将结构与 return 值一起连接到目标语言。通过这种方式,您可以创建一个适当的接口,其中 header 中没有给出实现。那不是虚拟析构函数的默认实现。如果不想使用接口,可以让 SWIG 和 Python 了解数据的表示方式。
接口header:foo.h
typedef struct _Foo Foo;
int foo_new(Foo **obj);
int foo_free(Foo *obj);
int foo_get_value_a(Foo *obj, int *result);
int foo_set_value_a(Foo *obj, int value);
int foo_get_value_b(Foo *obj, char **result);
int foo_set_value_b(Foo *obj, char *value);
SWIG 接口:foo.i
%module foo
%{
#include "foo.h"
%}
%include "typemaps.i"
%typemap(in, numinputs=0) Foo ** (Foo *temp) {
= &temp;
}
%typemap(argout) Foo ** {
PyObject* temp = NULL;
if (!PyList_Check($result)) {
temp = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, temp);
}
temp = SWIG_NewPointerObj(*, SWIGTYPE_p__Foo, SWIG_POINTER_NEW);
PyList_Append($result, temp);
Py_DECREF(temp);
}
%delobject foo_free; // Protect for double deletion
struct _Foo {};
%extend _Foo {
~_Foo() {
foo_free($self);
}
};
%ignore _Foo;
接口的一些实现:foo.c
%include "foo.h"
#include "foo.h"
#include "stdlib.h"
#include "string.h"
struct FooImpl {
char* c;
int i;
};
int foo_new(Foo **obj)
{
struct FooImpl* f = (struct FooImpl*) malloc(sizeof(struct FooImpl));
f->c = NULL;
*obj = (Foo*) f;
return 0;
}
int foo_free(Foo *obj)
{
struct FooImpl* impl = (struct FooImpl*) obj;
if (impl) {
if (impl->c) {
free(impl->c);
impl->c = NULL;
}
}
return 0;
}
int foo_get_value_a(Foo *obj, int *result)
{
struct FooImpl* impl = (struct FooImpl*) obj;
*result = impl->i;
return 0;
}
int foo_set_value_a(Foo *obj, int value)
{
struct FooImpl* impl = (struct FooImpl*) obj;
impl->i = value;
return 0;
}
int foo_get_value_b(Foo *obj, char **result)
{
struct FooImpl* impl = (struct FooImpl*) obj;
*result = impl->c;
return 0;
}
int foo_set_value_b(Foo *obj, char *value)
{
struct FooImpl* impl = (struct FooImpl*) obj;
int len = strlen(value);
if (impl->c) {
free(impl->c);
}
impl->c = (char*)malloc(len+1);
strcpy(impl->c,value);
return 0;
}
构建脚本
#!/usr/bin/env python
from distutils.core import setup, Extension
import os
os.environ['CC'] = 'gcc';
setup(name='foo',
version='1.0',
ext_modules =[Extension('_foo',
['foo.i','foo.c'])])
用法:
import foo
OK, f = foo.foo_new()
OK = foo.foo_set_value_b(f, 'Hello world!')
OK = foo.foo_free(f)
OK, f = foo.foo_new()
# Test safe to double delete
del f