2012-12-17 21 views
7

Không biết nhiều về ctypes, chỉ mới bắt đầu làm việc với nó.Làm thế nào để vượt qua con trỏ trở lại trong ctypes?

Tôi có một hàm đơn giản trong C-like dll, trả về một con trỏ đến chuỗi được tạo động.
Nó hoạt động tốt, nhưng, bởi vì tôi được cấp phát bộ nhớ bằng tay cho chuỗi, tôi nên giải phóng nó sau khi sử dụng.

Tôi có một cái gì đó như thế này:

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

Nhưng tôi không có bất kỳ ý tưởng, làm thế nào tôi có thể vượt qua được con trỏ trở lại để xóa bằng Python?

+0

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

Trả lời

7

Bạn đang đi đúng hướng.

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

Và trong 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) 
+2

'stringdup.restype' cần phải được đặt thành loại con trỏ, chẳng hạn như' POINTER (c_char) 'vì loại kết quả mặc định là' int' 32 bit. Để có được một chuỗi Python, bạn có thể sử dụng 'cast (p, c_char_p) .value' hoặc ' c_char_p.from_buffer (p) .value'. – eryksun

8

Thông thường mỗi chức năng bạn sử dụng trong ctypes nên có đối số của nó và kiểu trả về tuyên bố như vậy Python có thể kiểm tra số lượng chính xác và loại đối số và chuyển đổi đối số đối tượng Python cho đúng đối tượng dữ liệu C. Thật không may trong trường hợp này, giá trị trả về bình thường cho func sẽ là c_char_p, nhưng ctypes cố gắng hữu ích và chuyển đổi giá trị trả về c_char_p thành chuỗi Python, mất quyền truy cập vào giá trị con trỏ C thô. Thay vào đó, bạn có thể khai báo kiểu trả về là c_void_p và sử dụng cast để truy lục giá trị chuỗi, để lại giá trị trả về là đối tượng c_char_p.

Dưới đây là một ví dụ (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)