2017-08-25 1 views
1

私はctypes経由でPythonにいくつかのC++クラスを拡張しています。 まず、GDBとコードでアドレスがNULLでないことを確認してください。これは実際にはNULLと等しくありません。私はprintf経由でポインタを出力しようとし、アドレスを出力しますが、ポインタを含む次の行のコードはセグメンテーションフォールトをスローします。奇妙なことは、そのprintfステートメントがなければ、printfステートメントの後に来る次のコード行が機能するということです。しかし、ポインタを含む次の関数は、printfのようにセグメンテーションフォールトを投げます。ここで ctypesはポインタを複数回参照解除することを許可していません

は、参考のために私のコードです:

C++ - > 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 7.12.50
  • のPython 3.6
  • SDL 2.0.3
+0

真剣に、ちょうど 'cffi'を使用して、あなたの人生ははるかにsanerされます。 – o11c

+0

'jetfuelsofilepath'を一度ロードしていますか?もしそうなら、このデザインは奇妙です。ライブラリのロードを移動し、関数プロトタイプをクラススコープまたはモジュールスコープに定義します。すべてのインスタンスまたはメソッドが呼び出されるたびに実行しないでください。また、プロトタイプが正しく設定されていれば、時間を無駄にせず、引数を手動で 'c_void_p'と' c_wchar_p'インスタンスとしてラップすることでコードを浪費する必要はありません。 – eryksun

答えて

0

restypeをに設定しています:

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

デフォルトでは、ポインタを台無しにされ、intです。他の機能には同様の処理が必要です。物事をきちんと整理するために、すべての作業を1か所で行うことをおすすめします(例:load_jetfuel_library)。

+0

ありがとうございます。私は明日それが動作するかどうかを確認し、それがあればこの答えを受け入れるようにマークします。 – Insight

関連する問題