0

我是 swig 的新手,我有以下无法修复的功能:

int get_list(IN const char * string, OUT struct entry ** results);

其中struct entry定义:

struct flux_entry
{
    char * addr_str;
    char cc[2];
};

入口结构已正确转换为 python 类。我用谷歌搜索但找不到任何我可以使用的解释。
我想让它返回一个元组:(原始get_listint返回值,条目python对象的python列表,基于结果缓冲区),但不知道如何将C条目转换为argout代码片段中的python对象. 到目前为止,我已经设法做到了:

%typemap(argout) struct entry **
{
    PyObject *o = PyList_New(0);
    int i;
    for(i=0; $1[i] ; i++)
    {
        PyList_Append(o, SWIG_HOW_TO_CONVERT_TO_PYOBJECT($1[i]));
    }
    $result = o;
}

我应该用什么代替SWIG_HOW_TO_CONVERT_TO_PYOBJECT?passresults应该是指向 (struct entry *) 类型的指针,NULL在调用之前设置为,get_list并且应该设置为分配的struct entry *指针数组。也许一个小的包装函数可以让这更容易?

在计算(内部)需要多少个元素之后,struct entry使用 C 函数在 C 函数中分配数组,并以指示数组结尾的指针结束。mallocget_listNULL

我还想确保它在某个地方被释放:)

谢谢!

4

1 回答 1

1

这至少应该为您提供一个可行的起点。我仍然不确定数据是如何返回的,因为要返回一个指针数组以便最后一个为 NULL 我认为你需要一个struct entry ***,所以我只是将addr_str = NULL最后一个设置为哨兵,然后将部分基于输入字符串的一些虚拟数据放入字段中。根据需要进行修改以满足您的需要:

%module example

// Insert the structure definition and function to wrap into the wrapper code.
%{
  struct entry {
    char* addr_str;
    char cc[2];
  };

  int get_list(const char* string, struct entry** results)
  {
    *results = malloc(3 * sizeof(struct entry));
    (*results)[0].addr_str = malloc(10);
    strcpy((*results)[0].addr_str,"hello");
    (*results)[0].cc[0] = string[0];
    (*results)[0].cc[1] = string[1];
    (*results)[1].addr_str = malloc(10);
    strcpy((*results)[1].addr_str,"there");
    (*results)[1].cc[0] = string[2];
    (*results)[1].cc[1] = string[3];
    (*results)[2].addr_str = NULL;
    return 0;
  }
%}

#include <typemaps.i>

// Define the structure for SWIG
struct entry {
  char* addr_str;
  char cc[2];
};

// Define a set of typemaps to be used for an output parameter.

// This typemap suppresses requiring the parameter as an input.
// A temp variable is created and passed instead.
%typemap(in,numinputs=0) struct entry **OUTPUT (struct entry* temp) %{
  $1 = &temp;
%}

// Build a list of tuples containing the two entries from the struct.
// Append the new Python list object to the existing "int" result.
%typemap(argout) struct entry **OUTPUT {
  int i = 0;
  PyObject* out = PyList_New(0);
  while((*$1)[i].addr_str != NULL)
  {
    //PyObject* t = PyTuple_New(2);
    //PyTuple_SET_ITEM(t,0,PyBytes_FromString((*$1)[i].addr_str));
    //PyTuple_SET_ITEM(t,1,PyBytes_FromStringAndSize((*$1)[i].cc,2));
    //PyList_Append(out,t);
    //Py_DECREF(t);
    PyObject* s = SWIG_NewPointerObj(*$1+i,$descriptor(struct entry*),0);
    PyList_Append(out,s);
    Py_DECREF(s);
    ++i;
  }
  $result = SWIG_AppendOutput($result,out);
}

// Since a Python object was created and the data copied for each entry struct,
// free the memory returned in the structure.
//%typemap(freearg) struct entry **OUTPUT {
//  int i=0;
//  while((*$1)[i].addr_str != NULL) {
//    free((*$1)[i].addr_str);
//    ++i;
//  }
//  free(*$1);
//}

// Apply the OUTPUT typemap set to the "results" parameter.
%apply struct entry **OUTPUT {struct entry** results};

// Finally, define the function for SWIG
int get_list(const char* string, struct entry** results);

演示(Python 3.3):

>>> import example
>>> example.get_list('abcd')
[0, [(b'hello', b'ab'), (b'there', b'cd')]]

希望有帮助。

编辑

我注释掉了元组的创建,只保存了entry*代理。这不会泄漏 Python 对象,但entry*不会释放分配给 an 使用的内存。尽管我正在尝试使用%extend.

于 2013-06-23T23:39:48.257 回答