无法使用 SWIG 将 C++ 中创建的 UTF-16 字符串缓冲区转换为 python



我有一个C++函数想在Python中使用:

struct DataWrap
{
    wchar_t* data;
    int size;
}
extern int fun1( const char* szInBuffer, unsigned int inSize,DataWrap* buff);

fun1 采用大小为 inSizeszInBuffer 中给出的 char 数组,并以 dataWrap->data 返回新分配的 UTF-16 字符串

我想使用这个来自 Python fun1的函数。

%typemap(argout) DataWrap* buff{
                int byteorder = -1;
                $input = PyUnicode_DecodeUTF16( (const char*)($1->data), ($1->size)*sizeof(wchar_t) , NULL, &byteorder);
}

这确实有效,但这里有内存泄漏因为fun1分配的dataWrap->data永远不会发布。

我试图像这样解决这个问题:

%typemap(argout) DataWrap* buff{
            int byteorder = -1;
            $input = PyUnicode_DecodeUTF16( (const char*)($1->data), ($1->size)*sizeof(wchar_t) , NULL, &byteorder);
            delete $1;
        }

现在代码崩溃了。

我做错了什么?这是为什么使用SWIG以获得UTF-16字符串进入Python的正确原因吗?

尝试freearg类型映射:

%typemap(freearg) DataWrap *buff {
    delete $1->data;
}

另外,你有delete $1;. 应该delete $1->data吗?

编辑

我在处理此问题时发现了另一个可能与您的问题有关的问题。 如果您使用的是 Windows,并且您的 fun1 实现与 SWIG 包装器代码位于不同的 DLL 中,请确保使两个 DLL 链接到同一个 C 运行时 DLL(例如,通过 Microsoft VC++ 中的 /MD 编译器开关),因为内存随后将在一个 DLL 中分配(我假设new)并在另一个 DLL 中释放。

这是我正在使用的代码。 它可能会对你有所帮助。 它还包括一个类型映射,用于消除从 Python 发送字符串和大小,以及一个类型映射来生成临时 DataWrap 对象,因此不必传递它。 在实现文件中x.cpp我伪造了一个将字符串转换为 UTF16 的实现,该实现仅适用于简单的 ASCII 字符串。

另请注意,我在不使用freearg类型映射的情况下使其工作,尽管使用类型映射也对我有用。

生成文件

_x.pyd: x_wrap.cxx x.dll
    cl /MD /nologo /LD /Zi /EHsc /W4 x_wrap.cxx /Id:devpython27include -link /LIBPATH:d:devpython27libs /OUT:_x.pyd x.lib
x.dll: x.cpp x.h
    cl /MD /nologo /Zi /LD /EHsc /W4 x.cpp
x_wrap.cxx: x.h x.i
    swig -python -c++ x.i

十、一

%module x
%begin %{
#pragma warning(disable:4127 4211 4706)
%}
%{
    #include "x.h"
%}
%include <windows.i>
%typemap(in) (const char *szInBuffer,unsigned int inSize) {
   if (!PyString_Check($input)) {
       PyErr_SetString(PyExc_ValueError, "Expecting a string");
       return NULL;
   }
   $1 = PyString_AsString($input);
   $2 = PyString_Size($input);
}
%typemap(in, numinputs=0) DataWrap* buff (DataWrap temp) {
   $1 = &temp;
}
%typemap(argout) DataWrap* buff {
    int byteorder = -1;
    $result = PyUnicode_DecodeUTF16((const char*)($1->data), ($1->size)*sizeof(wchar_t), NULL, &byteorder);
    delete [] $1->data;
}
%include "x.h"

X.H

#ifdef API_EXPORTS
#   define API __declspec(dllexport)
#else
#   define API __declspec(dllimport)
#endif
struct DataWrap
{
    wchar_t* data;
    int size;
};
extern "C" API void fun1(const char* szInBuffer, unsigned int inSize, DataWrap* buff);

x.cpp

#include <stdlib.h>
#define API_EXPORTS
#include "x.h"
API void fun1(const char* szInBuffer, unsigned int inSize, DataWrap* buff)
{
    unsigned int i;
    buff->size = inSize;
    buff->data = new wchar_t[inSize];
    for(i = 0; i < inSize; i++)
        buff->data[i] = szInBuffer[i];
}

输出

Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import x
>>> x.fun1('abc')
u'abc'

最新更新