2017-08-25 84 views
1

我一直在通過ctypes將一些C++類擴展爲python。 我首先嚐試通過GDB和代碼驗證地址不等於NULL。它確實不等於NULL。我嘗試通過printf打印指針,並將地址輸出,但涉及指針的下一行代碼會引發分段錯誤。奇怪的是,如果沒有這個printf語句,printf語句後面的下一行代碼將會工作。然而,涉及指針的下一個函數會像printf一樣引發一個分段錯誤。ctypes不允許多次提取指針

這裏是我的參考代碼:

C++ - 「çctypes的包裝器

#include <jetfuelmedia.h> 

#define MAX_FILE_NAME_SIZE 1024 

extern "C"{ 
jetfuel::media::Music *Music_new(){ 
    return new jetfuel::media::Music(); 
} 

void Music_delete(jetfuel::media::Music *music){ 
    puts("Destroyed Music object"); 
    delete music; 
} 

bool Music_is_music_playing(){ 
    return Mix_PlayingMusic(); 
} 

bool Music_is_music_paused(){ 
    return Mix_PausedMusic(); 
} 

bool Music_load_music_file(jetfuel::media::Music *music, 
          const wchar_t *musicfilepath){ 
    char musicfilepathchar[MAX_FILE_NAME_SIZE]; 

    wcstombs(musicfilepathchar,musicfilepath, 
      MAX_FILE_NAME_SIZE); 

    puts("Music file is:"); 
    puts(musicfilepathchar); 
    puts("Music ref is:"); 
    printf("%p",music); 

    if(!music->Load_music_file(musicfilepathchar)){ 
     puts(musicfilepathchar); 
     puts(Mix_GetError()); 
     return false; 
    } 

    puts("C/C++ code ran"); 

    return true; 
} 

bool Music_play(jetfuel::media::Music *music){ 
    puts("C/C++ Play code ran"); 
    return music->Play(); 
} 

void Music_pause(jetfuel::media::Music *music){ 
    music->Pause(); 
} 

void Music_resume(jetfuel::media::Music *music){ 
    music->Resume(); 
} 

const char *Get_music_error(){ 
    const char *sdlerror = Mix_GetError(); 

    if(sdlerror == NULL){ 
     return "Music object was equal to NULL"; 
    } 
    return Mix_GetError(); 
} 
} 

Python類包裝:

from ctypes import cdll 
from ctypes import c_wchar_p 
from ctypes import c_void_p 
from ctypes import c_bool 

class music(): 
    _jetfuel = None; 
    _musicref = None; 

    def __init__(self,jetfuelsofilepath): 
     self._jetfuel = cdll.LoadLibrary(jetfuelsofilepath); 
     self._musicref = self._jetfuel.Music_new(); 

    def __enter__(self): 
     return self; 

    def __exit__(self, exc_type, exc_value, traceback): 
     if(self._musicref != None): 
      self._jetfuel.Music_delete(c_void_p(self._musicref)); 

    def is_music_playing(self): 
     return self._jetfuel.Music_is_music_playing(); 

    def is_music_paused(self): 
     return self._jetfuel.Music_is_music_paused(); 

    def load_music_file(self, musicfilepath): 
     loadmusicfile = self._jetfuel.Music_load_music_file; 
     loadmusicfile.argtypes = [c_void_p, c_wchar_p]; 
     loadmusicfile.restype = c_bool; 

     return loadmusicfile(c_void_p(self._musicref), 
         c_wchar_p(musicfilepath)); 

    def play(self): 
     return self._jetfuel.Music_play(c_void_p(self._musicref)); 

    def pause(self): 
     self._jetfuel.Music_pause(c_void_p(self._musicref)); 

    def resume(self): 
     self._jetfuel.Music_resume(c_void_p(self._musicref)); 

    def print_debug(self): 
     print("Music ref is ="+str(c_void_p(self._musicref))); 

    def get_music_error(self): 
     return self._jetfuel.Get_music_error(); 

我怎樣才能使此代碼工作的指針,可以多次解除引用?

如果這涉及到什麼,我的系統的信息是:

  • 的Ubuntu 17.04 64位
  • GCC(G ++)5.4.1
  • GDB 50年12月7日
  • 的Python 3.6
  • SDL 2.0.3
+0

說真的,只要用'cffi',你的生活就會變得更加健康。 – o11c

+0

你只是加載'jetfuelsofilepath'一次嗎?如果是這樣,這種設計很奇怪。移動加載庫並將函數原型定義到類或模塊範圍。不要爲每個實例或每次調用某個方法時執行此操作。另外,如果原型設置正確,則不必浪費時間並將代碼手動包裝爲'c_void_p'和'c_wchar_p'實例。 – eryksun

回答

0

您忘記設置restypeMusic_new

def __init__(self,jetfuelsofilepath): 
    self._jetfuel = cdll.LoadLibrary(jetfuelsofilepath) 
    self._jetfuel.Music_new.restype = c_void_p 
    self._musicref = self._jetfuel.Music_new() 

默認爲int,其攪亂指針。其他功能需要類似的處理。爲了保持整潔,我建議你在一個地方做所有事情(例如功能load_jetfuel_library)。

+0

謝謝。我會在明天測試一下,看看它是否有效,然後標記接受的答案。 – Insight