2012-11-18 28 views
14

私はctypesを持つC/C++ライブラリからPythonにいくつかの文字列を取得したいと思います。Python ctypes:メモリを解放する方法は?無効なポインタエラーを取得する

コードlibに:

const char* get(struct something *x) 
{ 
    [...] 
    // buf is a stringstream 
    return strdup(buf.str().c_str()); 
} 

void freeme(char *ptr) 
{ 
    free(ptr); 
} 

Pythonコード:私のコードは次のようになり、私は()c_strを印刷する場合

fillprototype(lib.get, c_char_p, POINTER(some_model)]) 
fillprototype(lib.freeme, None, [c_char_p]) 

// what i want to do here: get a string into python so that i can work 
// with it and release the memory in the lib. 
c_str = lib.get(some_model) 
y = ''.join(c_str) 
lib.freeme(c_str) 

、すべてがそこにあります。最後のPythonの行に問題がある(またはそうであると思われる)。私はメモリを解放することはできません - ライブラリが間違ったポインタを取得しています。私はここで間違っていますか? (そしてboost :: pythonなどを提案しないでください)。

*** glibc detected *** python2: munmap_chunk(): invalid pointer: 0x00000000026443fc *** 
+2

なぜ 'get'は' const char * 'を返しますが' freeme'は 'char *'を期待していますか?あなたの呼び出し元がconstを投げ捨てることを期待していますか? –

+0

良い点..残念ながら、それは問題を解決しませんでした。 –

+0

この32ビットまたは64ビットのコードですか?エラーが発生したコードの行は何ですか?必ずしも 'free(ptr) 'であるとは限りません。 –

答えて

18

デビッド・シュワルツが指摘したように、あなたがc_char_pにRESTYPEを設定した場合、ctypesのは、通常のPython文字列オブジェクトを返します。これを回避するための簡単な方法は、void *を使用することで、結果キャスト:

string.c:

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

char *get(void) 
{ 
    char *buf = "Hello World"; 
    char *new_buf = strdup(buf); 
    printf("allocated address: %p\n", new_buf); 
    return new_buf; 
} 

void freeme(char *ptr) 
{ 
    printf("freeing address: %p\n", ptr); 
    free(ptr); 
} 

Pythonの使用法:あなたが使用することもでき

from ctypes import * 

lib = cdll.LoadLibrary('./string.so') 
lib.freeme.argtypes = c_void_p, 
lib.freeme.restype = None 
lib.get.argtypes = [] 
lib.get.restype = c_void_p 

>>> ptr = lib.get() 
allocated address: 0x9facad8 
>>> hex(ptr) 
'0x9facad8' 
>>> cast(ptr, c_char_p).value 
'Hello World' 
>>> lib.freeme(ptr) 
freeing address: 0x9facad8 

c_char_pのサブクラスです。 ctypesは単純型のサブクラスに対してgetfuncを呼び出さないことが分かります。

class c_char_p_sub(c_char_p): 
    pass 

lib.get.restype = c_char_p_sub 

value属性は文字列を返します。より汎用的なc_void_pとして、freemeのパラメータをそのままにすることができます。これは、任意のポインタ型または整数アドレスを受け入れます。

+1

それは完璧に働いた、ありがとう! –

+0

右。ありがとう。 –

関連する問題