2012-12-17 8 views
7

Non so molto dei ctypes, solo recentemente ha iniziato a lavorarci.Come passare il puntatore di nuovo in ctypes?

Ho una semplice funzione in dll di tipo C che restituisce un puntatore alla stringa generata dinamicamente.
Sta funzionando bene, ma, poiché ho allocato manualmente la memoria per la stringa, dovrei liberarlo dopo l'uso.

ho qualcosa di simile:

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; 
    } 

Ma non ho alcuna idea, come posso passare ricevuto puntatore indietro per l'eliminazione in Python?

+0

Vedi http://stackoverflow.com/questions/7398575/deallocating-memory-for-objects-returned-to-python-through-ctypes. –

risposta

7

Sei sulla strada giusta.

// 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; 
} 

E in pitone:

# 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) 
+2

'stringdup.restype' deve essere impostato su un tipo di puntatore, ad esempio' POINTER (c_char) 'poiché il tipo di risultato predefinito è un' int' a 32 bit. Per ottenere una stringa Python, puoi usare 'cast (p, c_char_p) .value' o ' c_char_p.from_buffer (p) .value'. – eryksun

8

Normalmente ogni funzione si utilizza in ctypes dovrebbe avere i suoi argomenti e tipo di ritorno dichiarati in modo Python può controllare il numero e il tipo corretto di argomenti e convertire gli argomenti oggetto Python agli oggetti dati C corretti. Sfortunatamente in questo caso, il valore di ritorno normale per func è c_char_p, ma ctypes tenta di essere utile e convertire un valore di ritorno c_char_p in una stringa Python, perdendo l'accesso al valore del puntatore C non elaborato. Invece, è possibile dichiarare il tipo restituito come c_void_p e utilizzare cast per recuperare il valore stringa, che lascia il valore restituito come oggetto c_char_p.

Ecco un esempio (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)