2012-12-17 59 views
7

對ctypes瞭解不多,最近纔開始使用它。如何將指針傳回ctypes?

我在類C的dll一個簡單的函數返回一個指向動態生成的字符串。
它工作正常,但是,因爲我手動分配內存的字符串,我應該釋放它後使用。

我有這樣的事情:

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

但我沒有任何想法,怎麼能我通過在Python收到指針回來進行刪除嗎?

+0

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

回答

7

你在正確的軌道上。

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

而在蟒蛇:

# 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'需要設置爲一個指針類型,比如'POINTER(c_char)',因爲默認的結果類型是一個32位的'int'。要獲得一個Python字符串,可以使用'cast(p,c_char_p).value'或者'c_char_p.from_buffer(p).value'。 – eryksun

8

通常每次在​​使用應該有它的參數和返回類型聲明所以Python可以檢查正確的參數數量和類型轉換的Python對象的參數功能到正確的C數據對象。不幸的是在這種情況下,func正常的返回值將是c_char_p,但​​嘗試是有益的,一個c_char_p返回值轉換爲一個Python字符串,還能訪問原始的C指針值。相反,你可以聲明返回類型爲c_void_p和使用cast檢索字符串值,其離開返回值的c_char_p對象。

下面是一個示例(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)