python - c_int()
¿Cómo pasar el puntero en ctypes? (2)
No sé mucho sobre los tipos, hace poco empecé a trabajar con él.
Tengo una función simple en C-like dll que devuelve un puntero a la cadena generada dinámicamente.
Está funcionando bien, pero, como he asignado manualmente la memoria para la cadena, debería liberarla después de su uso.
Tengo algo como esto:
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;
}
Pero no tengo ni idea, ¿cómo puedo pasar el puntero recibido para su eliminación en Python?
Estás en el camino correcto.
// TestDLL.cpp
#include <string.h> // strcpy
extern "C" __declspec(dllexport) char* stringdup(const char* str) {
char* p = new char[strlen(str)+1];
strcpy(p,str);
return p;
}
// if you have no good reason to use void*, use the type
// you''ve allocated. while it usually works for built-in
// types, it wouldn''t work for classes (it wouldn''t call
// the destructor)
extern "C" __declspec(dllexport) void stringfree(char* ptr) {
// you don''t need to check for 0 before you delete it,
// but if you allocate with new[], free with delete[] !
delete [] ptr;
}
Y en python:
# Test.py
import ctypes
lib = ctypes.cdll.TestDLL
# this creates a c-style char pointer, initialized with a string whose
# memory is managed by PYTHON! do not attempt to free it through the DLL!
cstr = ctypes.c_char_p("hello ctypes")
# call the dll function that returns a char pointer
# whose memory is managed by the DLL.
p = lib.stringdup(cstr)
# p is just an integer containing the memory address of the
# char array. therefore, this just prints the address:
print p
# this prints the actual string
print ctypes.c_char_p(p).value
# free the memory through the DLL
lib.stringfree(p)
Normalmente, cada función que use en ctypes
debe tener sus argumentos y tipo de declaración declarados para que Python pueda verificar el número y tipo correcto de argumentos y convertir los argumentos del objeto Python en los objetos de datos C correctos. Desafortunadamente en este caso, el valor de retorno normal para func
sería c_char_p
, pero ctypes
intenta ser útil y convierte un valor de retorno c_char_p
en una cadena de Python, perdiendo acceso al valor del puntero en C sin formato. En su lugar, puede declarar el tipo de devolución como c_void_p
y usar cast
para recuperar el valor de cadena, que deja el valor de retorno como un objeto c_char_p
.
Aquí hay un ejemplo (Python 3):
import ctypes
func = ctypes.cdll.TestDLL.func
func.argtypes = [ctypes.c_char_p,ctypes.c_char_p]
func.restype = ctypes.c_void_p
freeMem = ctypes.cdll.TestDLL.freeMem
freeMem.argtypes = [ctypes.c_void_p]
freeMem.restype = None
s = func(b''abcdef'',b''ghijkl'')
s = ctypes.cast(s,ctypes.c_char_p)
print(s.value)
freeMem(s)