Don't know much about ctypes, just recently began working with it.
I have a simple function in C-like dll which returns a pointer to the dynamically generated string.
It is working fine, but, because i manually allocated memory for the string, i should free it after use.
I have something like this:
extern "C" char* DLL_EXPORT func(const char* str1, const char* str2)
{
return getSomeString(str1, str2);
}
// Goal is to call this function correctly from Python.
extern "C" void DLL_EXPORT freeMem(void *mem)
{
if(mem!=NULL)
delete mem;
}
But i don't have any idea, how can i pass received pointer back for deletion in Python?
ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
It is a big C++ codebase with a (very) thin python wrapper which uses CDLL to load the C++ and call some C functions that are available to allow primitive python scripting of the code.
Normally each function you use in ctypes
should have its arguments and return type declared so Python can check for the correct number and type of arguments and convert Python object arguments to the correct C data objects. Unfortunately in this case, the normal return value for func
would be c_char_p
, but ctypes
tries to be helpful and convert a c_char_p
return value to a Python string, losing access to the raw C pointer value. Instead, you can declare the return type as POINTER(c_char)
and use cast
to retrieve the string value, which leaves the return value a LP_c_char
object that can be freed.
Here's an example. Note that declaring the correct .restype
is especially important for 64-bit Python, since the default return type is c_int
(32-bit) and a 64-bit pointer could be truncated. This code is tested with both 32- and 64-bit builds.
test.c
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API char* func(const char* str1, const char* str2) {
size_t len = strlen(str1) + strlen(str2) + 1;
char* tmp = malloc(len);
strcpy_s(tmp, len, str1);
strcat_s(tmp, len, str2);
return tmp;
}
API void freeMem(void *mem) {
free(mem);
}
test.py
import ctypes as ct
dll = ct.CDLL('./test')
dll.func.argtypes = ct.c_char_p,ct.c_char_p
dll.func.restype = ct.POINTER(ct.c_char)
dll.freeMem.argtypes = ct.c_void_p,
dll.freeMem.restype = None
# Helper function to extract the return value as a Python object
# and always free the pointer.
def freeMem(a,b):
p = dll.func(b'abcdef', b'ghijkl')
print(p)
s = ct.cast(p, ct.c_char_p).value
dll.freeMem(p)
return s
print(freeMem(b'abcdef', b'ghijkl'))
Output:
<ctypes.LP_c_char object at 0x00000279D7959DC0>
b'abcdefghijkl'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With