我有一个 C++ 类
class EventHandler { virtual long readFromDaemon(void *buf, size_t count) = 0; };
以及使用它的 Python 程序
class Handler(EventHandler): def readFromDaemon(self, buf, count): ...
C++ 代码调用 EventHandler::readFromDaemon()。SWIG 转换参数并调用 Python 的 readFromDaemon():
long SwigDirector_EventHandler::readFromDaemon(void *buf, size_t count) { ... swig::SwigVar_PyObject obj0; obj0 = SWIG_NewPointerObj(SWIG_as_voidptr(buf), SWIGTYPE_p_void, 0 ); swig::SwigVar_PyObject obj1; obj1 = SWIG_From_size_t(static_cast< size_t >(count)); ... swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)"readFromDaemon"); swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(PyObject *)obj1, NULL);
我想将 (void *buf, size_t count) 转换为 PyBytesObject
def readFromDaemon(self, buf): # buf is bytes
但我没有找到实现它的方法。
%typemap(in) (void *buf, size_t count) { ... } does not help.
这是读取和写入 C 数据缓冲区的示例。我的示例中的 C 函数是:
void read(void* buf, size_t count); void write(const void* buf, size_t count);
SWIG 接口文件:
%module x %include <exception.i> // Handle an input-only (const) buffer. // A single Python input is translated into a buffer and a size. %typemap(in) (const void *buf, size_t count) (Py_ssize_t tmp) %{ if(PyBytes_AsStringAndSize($input,(char**)&$1,&tmp) == -1) return NULL; $2 = tmp; %} // Handle an output-only (non-const) buffer. // The single integer Python input is allocated in a temporary // buffer and the pointer and its size are created as C++ parameters. %typemap(in,numinputs=1) (void *buf, size_t count) (long tmp) %{ if(!PyLong_Check($input)) SWIG_exception(SWIG_TypeError,"expected integer"); tmp = PyLong_AsLong($input); if(tmp < 1 || tmp > 65535) SWIG_exception(SWIG_ValueError,"expected value 1-65535"); $2 = tmp; $1 = new char[$2]; %} // The pair of output arguments are translated into a single // Python bytes object and appended to any existing return value. %typemap(argout) (void *buf, size_t count) (PyObject* po) %{ po = PyBytes_FromStringAndSize((char*)$1,$2); $result = SWIG_Python_AppendOutput($result,po); %} // Free the temporary buffer created in the "in" typemap. %typemap(freearg) (void* buf, size_t count) %{ delete $1; %} // SWIG will wrap these two functions prototypes. void read(void* buf, size_t count); void write(const void* buf, size_t count); // Implementation %{ #include <iostream> void write(const void* buf, size_t count) { char* tmp = (char*)buf; for(size_t i = 0; i < count; i++) std::cout << i << ": " << (int)tmp[i] << std::endl; } void read(const void* buf, size_t count) { char* tmp = (char*)buf; for(size_t i = 0; i < count; i++) tmp[i] = (char)i; } %}
演示:
>>> import x >>> x.read(10) b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t' >>> x.read(-1) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: expected value 1-65535 >>> x.read(1000000) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: expected value 1-65535 >>> x.write(b'abcdefg') 0: 97 1: 98 2: 99 3: 100 4: 101 5: 102 6: 103 >>> x.write(12) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: expected bytes, int found