SWIG:如何使用 %apply 返回结构? “未定义类型映射”警告

Posted

技术标签:

【中文标题】SWIG:如何使用 %apply 返回结构? “未定义类型映射”警告【英文标题】:SWIG: How to return a struct using %apply? 'No typemaps defined' warning 【发布时间】:2016-08-08 23:16:07 【问题描述】:

我目前有一个函数,它使用结构作为缓冲区来返回一些信息,如下所示:

int example_reader(int code, void* return_struct);

我的目标是这样当我使用 SWIG 包装这个函数以便它可以在 Python 中使用时,我将返回结构以及函数的常规返回值。到目前为止,我一直在使用 %apply 命令,如下所示:

%apply struct ret_struct *OUTPUT void* return_struct;

但是,当我将上述行添加到我的 .i 文件并尝试运行 SWIG 时,我收到以下警告:

“警告 453:无法应用(struct ret_struct *OUTPUT。未定义类型映射”

我相信我包含了定义我要返回的结构的 .h 文件,所以我很难确定问题所在。如果问题似乎涉及结构的不正确包含,请纠正我。我已经尝试阅读 SWIG 文档以及其他 Stack Overflow 帖子,以了解问题可能是什么,但到目前为止我还没有弄清楚。这个问题有点棘手,因为我试图返回一个指向结构的 void 指针,而我试图包装的代码可能有多种结构供我返回。处理这个结构的返回的明智方法是什么?谢谢!

【问题讨论】:

您的目标语言需要struct ret_struct 的定义,因此您不能返回void*。此外,如果要分配结构,则需要双指针或指针引用。一个典型的场景是定义一个接口typedef struct ReturnStructIF,并让一个函数生成这样一个接口的实例int CreateSpecializedStructure(ReturnStructIF** obj),并为这个接口定义一个函数。 您能举个例子吗?谢谢! 完成。如果您的构造函数不返回 0(表示成功),您可以考虑将以 SWIG_NewPointerObj 开头的最后 3 行移到 if 子句中以仅返回错误代码。 【参考方案1】:

我在这里给出了一个完整的 C 示例,其中接口用于将结构与返回值一起返回给目标语言。通过这种方式,您可以制作一个适当的接口,其中标题中没有给出任何实现。这不是虚拟析构函数的默认实现。如果不想使用接口,可以让 SWIG 和 Python 知道数据是如何表示的。

接口头: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) 
  $1 = &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(*$1, 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

【讨论】:

感谢您的帮助,示例代码非常有用,让我可以解决我的问题。 你是this blog entry的作者吗?

以上是关于SWIG:如何使用 %apply 返回结构? “未定义类型映射”警告的主要内容,如果未能解决你的问题,请参考以下文章

用于包装无符号二进制数据的 SWIG 技术

在 Swig 中通过 ref 返回动态数组

SWIG:返回原始指针与共享 ptrs 的向量

将外部指针包装到 SWIG 数据结构中

如何使用 swig 从`unsigned int *`返回`uint []`

带有指针的C结构,如何Swig?