2012-12-17 27 views
7

ctypesについてよく知りませんが、ちょうど最近、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を参照してください:

は、ここでの例(Pythonの3)です。 –

答えて

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

とPythonで:Pythonは引数の正しい数と種類をチェックし、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'は、デフォルトの結果の型が32ビットの' int'なので 'POINTER(c_char)'のようなポインタ型に設定する必要があります。 Python文字列を取得するには、 'cast(p、c_char_p).value'または ' c_char_p.from_buffer(p).value'を使用できます。 – eryksun

8

あなたは​​に使う通常、各関数は、引数や戻り値の型を宣言している必要があります正しいCデータオブジェクトに変換します。残念ながらこの場合、funcの通常の戻り値はc_char_pになりますが、​​は有用であり、c_char_pの戻り値をPython文字列に変換して、生のCポインタ値にアクセスできなくなります。代わりに、戻り値の型をと宣言し、castを使用して文字列の値を取得すると、戻り値はc_char_pのままです。

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) 
関連する問題