如何在ctypes中生成字符数组并将其指针作为函数参数传递

时间:2019-01-31 22:36:00

标签: python c ctypes

我想使用ctypes在C ++中使用一些信息,这些信息包含在Python字符列表中的序列化缓冲区中。我已经尝试了以下方法,但是我不明白为什么我的参数类型抛出错误。

我有一些C ++代码的C包装器,形式为

extern "C" {
    special_object *special_object_new() { return new special_object(); }

    int function(special_object *O, int buffer_size, char *buffer) {
        char *buf = (char*) malloc(buffer_size);
        for(int i = 0; i < buffer_size; i++) buf[i] = buffer[i];
        O->do_something_in_cpp_with_buf(buf);
        free(buf);
        buf = NULL;
        return 0;
    }
}

我想从Python ctypes传递function字符缓冲区buf。此字符缓冲区最初在Python中以字符列表的形式出现,因此我首先使用

将其转换为C字符数组
import ctypes
import cdll
buf_c = (ctypes.c_char*len(buf))(*buf)

然后使用

将其强制转换为指针
buf_p = ctypes.cast(buf_c, ctypes.POINTER(ctypes.c_char))

具有类型

>>> <class 'ctypes.LP_c_char'>

我已经知道此缓冲区buf_size的大小,为整数。

我执行以下操作(加载库并声明函数参数),

lib = cdll.LoadLibrary('PATH_TO_LIB/lib.so')
lib.function.restype = ctypes.c_int
lib.function.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char)]

然后我创建包含该函数的类

class Special(object):
    def __init__(self):
        self.obj = lib.special_object_new()

    def py_function(self, buffer_size, buffer):
        res = lib.function(self.obj, buffer_size, buffer)

最后,我尝试称其为

s = Special()
s.py_function(ctypes.c_int(buf_size), buffer)

但是我得到了错误

ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type

制作指针时,我无法弄清楚我在做什么错?任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

必须为每个函数定义所有参数。这是一个工作示例:

test.cpp

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

#include <stdio.h>

struct special_object {
    special_object() {
        printf("created\n");
    }

    ~special_object() {
        printf("destroyed\n");
    }

    void print(char* buffer, int buffer_size) {
        for(int i = 0; i < buffer_size; i++)
            printf("%02X ",static_cast<unsigned char>(buffer[i]));
        printf("\n");
    }
};

extern "C" {
    API special_object *special_object_new() {
        return new special_object();
    }

    API void special_object_print(special_object *O, char *buffer, int buffer_size) {
        O->print(buffer, buffer_size);
    }

    API void special_object_delete(special_object *O) {
        delete O;
    }
}

test.py

from ctypes import *

lib = CDLL('test')
lib.special_object_new.argtypes = ()
lib.special_object_new.restype = c_void_p
lib.special_object_print.argtypes = c_void_p, c_char_p, c_int
lib.special_object_print.restype = None
lib.special_object_delete.argtypes = c_void_p,
lib.special_object_delete.restype = None

class Special:
    def __init__(self):
        self.obj = lib.special_object_new()
    def __del__(self):
        lib.special_object_delete(self.obj)
    def print(self,buffer):
        lib.special_object_print(self.obj,buffer,len(buffer))

s = Special()
s.print(bytes([0x01,0x02,0xaa,0x55]))
s.print(b'hello, world!')

输出:

created
01 02 AA 55
68 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
destroyed