2012-11-18 206 views
14

我想從C/C++庫中獲取一些字符串,並將它們轉換爲python。我的代碼看起來是這樣的:在LIBPython ctypes:如何釋放內存?獲取無效指針錯誤

代碼:

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

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

Python代碼:

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) 

如果我打印()c_str,一切都在那裏。問題是(或似乎是)在最後一個Python行中。我無法釋放內存 - 庫正在弄錯指針。我在這裏做錯了什麼? (並請不要建議boost :: python左右)。

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

爲什麼'get'返回'const char *',但'freeme'期望'char *'?你是否期望你的調用者拋棄const? –

+0

好點..不幸的是,沒有解決問題。 –

+0

這是32位還是64位的代碼?你知道錯誤發生在哪一行嗎?它不一定是「免費(ptr)」。 –

回答

18

正如大衛·施瓦茨指出,如果設置restype到c_char_p,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屬性返回字符串。您可以將參數freeme保留爲更通用的c_void_p。它接受任何指針類型或整數地址。

+1

非常好用,非常感謝! –

+0

對。謝謝。 –