swig python 通过引用 char** (char**&) 输出参数

swig python output parameter by reference of char** (char**&)

我在使用 swig 的 python 的 c++ 换行中苦苦挣扎,让我卡住的是通过引用 char**(char* 的列表)的输出参数。

我的c++是这样的:

class dict{

    int getKeys(const char **&keys, int &result_length)
}

我知道我需要使用typemap,我在swig接口文件(.i)中写到:

    %{
    #include "dict.hpp"
    %}

        %apply int &OUTPUT { int & };


        %typemap(in, numinputs=0) char **& (char **temp) {
           = &temp;
        }

        %typemap(argout) char**& %{
            int ntokens; 
            int itoken;

            for (ntokens = 0; *[ntokens] != NULL; ntokens++) { 
            }

            PyObject* temp = NULL;
            temp = $result;
            $result = PyList_New(ntokens);
            for (itoken = 0; itoken < ntokens; itoken++) {
                PyList_Append($result, PyUnicode_FromString( *[itoken] )); 
            }

            PyObject* list_temp = NULL;
            list_temp = $result;
            $result = PyList_New(1);

            PyList_SetItem($result, 0, temp);
            PyList_Append($result, list_temp);

            Py_DECREF(temp);
            Py_DECREF(list_temp);
        %}
        %typemap(freearg) char**& %{
            free(*);
        %}


    %include "dict.hpp"

编译.i文件没有问题,但是在python中使用时,python.exe已经停止工作

 resultCode, keys, keysCount = dict.getkeys()

我通过引用 char* 成功包装了输出参数:

%typemap(in, numinputs=0) char *& (char *temp) {
   = &temp;
}

%typemap(argout) char*&  %{
    PyObject* temp = NULL;
    temp = $result;
    $result = PyList_New(1);
    PyList_SetItem($result, 0, temp);
    PyList_Append($result, PyUnicode_FromString(*));
    Py_DECREF(temp);
%}
%typemap(freearg) char*& %{
    free(*);
%}

但是如何通过引用char**(char*的列表)来包装输出参数?有人可以帮忙吗?

一个问题是这一行:

PyList_Append($result, PyUnicode_FromString( *[itoken] )); 

应该是:

PyList_Append($result, PyUnicode_FromString( (*)[itoken] ));

$result 处理看起来很有趣,但我没有继续调试。我认为更好的解决方案是使用多参数类型映射。这是我想出的测试方法 (Windows OS):

dict.hpp

#ifdef EXPORTS
#   define API __declspec(dllexport)
#else
#   define API __declspec(dllimport)
#endif

API void getKeys(const char **& keys, int& result_length);

dict.cpp

#define EXPORTS
#include "dict.hpp"

API void getKeys(const char **& keys, int& result_length)
{
    result_length = 5;
    keys = new const char*[result_length];
    keys[0] = "abcd";
    keys[1] = "efgh";
    keys[2] = "ijkl";
    keys[3] = "mnop";
    keys[4] = "qrst";
}

dict.i

%module dict

%{
#include "dict.hpp"
%}

%include <windows.i>

%typemap(in,numinputs=0) (const char**& keys,int& result_length) (char **temp, int len) %{
   = &temp;
   = &len;
%}

%typemap(argout) (const char**& keys,int& result_length) (PyObject* obj) %{
    obj = PyList_New(*);
    for (int itoken = 0; itoken < *; itoken++) {
        PyList_SET_ITEM(obj, itoken, PyUnicode_FromString( (*)[itoken] )); 
    }
    $result = SWIG_Python_AppendOutput($result,obj);
%}

%typemap(freearg) (const char**& keys,int& result_length) %{
    delete [] *;
%}

%include "dict.hpp"

输出:

Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import dict
>>> dict.getKeys()
['abcd', 'efgh', 'ijkl', 'mnop', 'qrst']