3

私はctypesを使用して、DLLからPythonスクリプトにいくつかのC関数を公開しています。関数の1つは、動的なサイズの文字配列を返します。この配列の内容をPythonで読み取れるようにしたいだけでなく、プロパティハンドルを使用して、配列のメモリを解放します。

Cコードの例:

...

#ifdef __cplusplus
extern "C"
{
#endif
    __declspec(dllexport) char * WINAPI get_str()
    {
        int str_len = ... // figure out how long it is gonna be and set it here
        char *ary = (char *)malloc(sizeof(char) * str_len);

        // populate the array
        ...

        ary[str_len - 1] = '\0';

        return ary;
    }

#ifdef __cplusplus
}
#endif

DLLをビルドし、それが見つかる場所にコピーして、次のPythonコードを作成します。

import ctypes

my_dll = ctypes.WinDLL("MyDLLName.dll")

some_str = ctypes.string_at(my_dll.get_str())

print some_str

このコードはすべて、期待どおりに正しく機能します。私の質問は、ctypes.string_atが指定されたメモリ位置に文字列を作成するため、some_strがPythonインタープリターのスコープ外になると、そのメモリはガベージコレクションされますか、それとも手動で解放する必要がありますか?

4

1 に答える 1

5

string_at呼び出されたメモリの場所から完全に独立した、新しいメモリの場所に新しいPython文字列を作成します。

Pythonまたはctypesは、ネイティブコードが何を返したかを推測できません。それに関する限り、これは単なる数値です(この場合、これはたまたま有効なポインターです)。

したがって、経験則では、メモリを割り当てるCコードを作成する場合は、同等のCコードを作成して割り当てを解除し、Pythonコードを使用してctypesから解放されたCコードを呼び出す必要があります。

このような簡単なスクリプトと例では、単純に割り当てられた文字列であることがわかっているため、ctypesを使用してシステムfree関数を呼び出すことにより、Python側から直接解放できます。

つまり、返されたポインターをPython var :(適切なctypesポインター型にキャットする場合としない場合があります)に格納し、string_atを実行した後、次を使用します。

pointer = my_dll.get_str()
some_str = ctypes.string_at(pointer)
# This is windows specific - 
# on Posix, one have to load "libc.so" and use "free" from there:
ctypes.cdll.msvcrt.free(pointer)
于 2013-02-26T03:31:32.367 に答える