在SWIG中将可变char *传递给Python

时间:2013-11-28 09:38:48

标签: c++ python swig

我有一个我需要在Python中实现的纯虚拟类,所以它是从C ++框架中调用的。

档案example.h

/** Abstract reader to be implemented */
class Reader {
public:
    /// Read maximum of `n` bytes into `c`
    virtual int read(char *c, int n) = 0;
    virtual ~Reader() {}
};

void test(Reader &r);

档案example.cpp

#include "example.h"

void test(Reader &r) {
    char buf[] = {0, 0, 0};
    r.read(buf, 3);
}

SWIG界面:

%module(directors="1") example
%{
#include "example.h"
%}

%feature("director") Reader;
%include "example.h"

Python测试代码:

import example
class ReaderImpl(example.Reader):
    def __init__(self):
        example.Reader.__init__(self)

    def read(self, c, n):
        ''' Demo impl '''
        print type(c)
        return 0

example.test(ReaderImpl())

后者将打印<type 'str'>这对我没用,因为我应该写入缓冲区。所以,问题是:有没有办法告诉SWIG我宁愿为char *写一些东西,也许像ctypes数组一样?

2 个答案:

答案 0 :(得分:3)

查看http://www.swig.org/Doc1.3/Python.html#Python_nn48

中的31.7.4 String handling部分

改变并不是那么简单,因为字符串的长度可以改变。如果你真的想要一个数组或类似的东西,请查看有关如何定义自己的类型映射的文档。

考虑到python映射的开销,只需从read()返回一个字符串就可能会更好(更简单的代码)。

答案 1 :(得分:1)

我通过类型映射解决了这个问题:

%typemap(directorin) char * {
    $input = PyInt_FromLong((unsigned long)$1;
}

结果,实现将接收一个整数,可以将其转换为ctypes指针:

from ctypes import cast, c_char, POINTER

class ReaderImpl(example.Reader):
    def read(self, buf, n):
        ptr = cast(buf, POINTER(c_char))
        # populate ptr[0]...ptr[n-1]

另一种选择是从Reader继承一个中间类,并根据返回字符串的纯虚方法实现read。这个新方法将在Python中实现。