Reputation: 177
I want to use some information in C++ that is contained in a serialised buffer in a list of characters in Python, using ctypes. I have tried the following, but I don't understand why my argument types are throwing an error.
I have a C wrapper to some C++ code, of the form
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;
}
}
I would like to pass function
a character buffer buf
from Python ctypes. This character buffer originally appears in Python as a list of characters, so I first convert it to a C character array using
import ctypes
import cdll
buf_c = (ctypes.c_char*len(buf))(*buf)
and then cast it to a pointer using
buf_p = ctypes.cast(buf_c, ctypes.POINTER(ctypes.c_char))
which has a type
>>> <class 'ctypes.LP_c_char'>
I already know the size of this buffer, buf_size
, as an integer.
I execute the following (loading library and declaring function arguments),
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)]
Then I make the class containing the function,
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)
Finally, I try to call it, as
s = Special()
s.py_function(ctypes.c_int(buf_size), buffer)
but I get the error
ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type
I can't work out what I am doing wrong when I make the pointer? Any help would be appreciated!
Upvotes: 1
Views: 1782
Reputation: 177971
You must define all the arguments for each function. Here's a working example:
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!')
Output:
created
01 02 AA 55
68 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
destroyed
Upvotes: 3