2017-08-25 4 views
1

J'ai travaillé sur l'extension de classes C++ à python via ctypes. J'ai d'abord essayer de vérifier que l'adresse n'est pas égale à NULL via GDB et dans le code. Il n'est en effet pas égal à NULL. J'essaie d'imprimer le pointeur via printf et il imprime l'adresse, mais la prochaine ligne de code impliquant le pointeur jette une erreur de segmentation. Ce qui est étrange, c'est que sans cette instruction printf, la prochaine ligne de code qui viendrait après l'instruction printf fonctionnerait. Cependant, la fonction suivante qui impliquait le pointeur lancerait une erreur de segmentation comme avec printf.ctypes n'autorise pas la déréférence du pointeur plus d'une fois

Voici mon code de référence:

C++ -> C ctypes wrapper

#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(); 
} 
} 

wrapper classe 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(); 

Comment puis-je faire ce travail de code avec des pointeurs qui peuvent être déréférencé plusieurs fois?

Si cela concerne quelque chose, mon info système est:

  • Ubuntu 17.04 64 bits
  • GCC (G ++)
  • 5.4.1 GDB 7.12.50
  • Python 3.6
  • SDL 2.0.3
+0

Sérieusement, il suffit d'utiliser 'cffi', votre vie sera plus saine. – o11c

+0

Êtes-vous en train de charger 'jetfuelsofilepath' une fois? Si oui, cette conception est étrange. Déplacer le chargement de la bibliothèque et la définition des prototypes de fonctions dans la portée de classe ou de module. Ne le faites pas pour chaque instance ou chaque fois qu'une méthode est appelée. De plus, si les prototypes sont correctement définis, vous n'avez pas à perdre du temps et à encombrer le code avec des arguments qui enveloppent manuellement les arguments comme les instances 'c_void_p' et' c_wchar_p'. – eryksun

Répondre

0

Vous avez oublié de définir restype de Music_new:

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

La valeur par défaut est int, qui salit le pointeur. Les autres fonctions nécessiteront un traitement similaire. Pour garder les choses bien rangées, je vous suggère de faire tout cela en un seul endroit (par exemple, une fonction load_jetfuel_library).

+0

Merci. Je vais tester demain pour voir si cela fonctionne et ensuite marquer cette réponse acceptée si c'est le cas. – Insight