2017-04-25 4 views
0

J'accède à une bibliothèque partagée C++ à partir de Python. La bibliothèque partagée C++ gère un analyseur de signal et est distribuée sans la source.Python & CTypes Erreur de pointeur nul

L'une des fonctions nécessite la transmission d'une struct dans l'appel de fonction et je ne suis pas sûr de le faire correctement en utilisant ctypes.

La définition du struct dans le fichier d'en-tête est:

typedef struct saIQPacket { 
    float *iqData; 
    int iqCount; 
    int purge; 
    int dataRemaining; 
    int sampleLoss; 
    int sec; 
    int milli; 
} saIQPacket; 

Et la fonction que je finis par appeler:

SA_API saStatus saGetIQData(int device, saIQPacket *pkt); 

En python, j'ai créé une classe comme suit:

class IQPacketData (ct.Structure): 
    _fields_ = [('iqData',ct.c_float*48611), 
       ('iqCount',ct.c_int), 
       ('purge', ct.c_int), 
       ('dataRemaining', ct.c_int), 
       ('sampleLoss', ct.c_int), 
       ('sec', ct.c_int), 
       ('milli', ct.c_int)] 

J'utilise ensuite ce qui précède comme suit:

self.iqPurge = ct.c_int(0) 
self.iqDataRemaining = ct.c_int(0) 
self.iqSampleLoss = ct.c_int(0) 
self.secondsRemaining = ct.c_int(0) 
self.millisecondsRemaining = ct.c_int(0) 
self.iqarraySize = ct.c_int(24305) 
self.iqArr = (ct.c_float*48611)() 

self.saIQPacketData = IQPacketData(self.iqArr, 
         self.iqarraySize, 
         self.iqPurge, 
         self.iqDataRemaining, 
         self.iqSampleLoss, 
         self.secondsRemaining, 
         self.millisecondsRemaining) 

Après l'initialisation du dispositif, j'appeler la fonction comme suit:

err = self.dll.saGetIQData(self.deviceHandle,ct.pointer(self.saIQPacketData)) 

Lorsque la fonction est exécuté, il renvoie une valeur de -1 qui se traduit par une erreur de pointeur nul. Y a-t-il quelque chose qui ne va pas dans la façon dont je construis la structure et que je la passe dans l'appel de fonction?

+0

'iqData' est censé être un' 'char *, pas un tableau. Changez-le en 'ct.POINTER (ct.c_float)'. Vous pouvez toujours affecter un tableau au champ. ctypes est assez intelligent pour vérifier que le type d'élément de tableau est correct et stocke l'adresse dans le champ struct tout en gardant une référence au tableau sous-jacent dans les _objects de la structure. – eryksun

+0

Il n'est pas nécessaire d'envelopper manuellement les valeurs entières en tant qu'instances 'c_int'. De plus, l'appel peut utiliser 'ct.byref (self.saIQPacketData)' au lieu d'allouer un pointeur. – eryksun

+0

Merci @eryksun. changer le type d'iqData et passer un pointeur au constructeur a corrigé le problème. – wgebers

Répondre

0

Comme suggéré par @eryksun dans les commentaires, le problème était de type. Code de travail ci-dessous pour référence future:

Le struct doit être:

import ctypes as ct 

class IQPacketData (ct.Structure): 
_fields_ = [('iqData',ct.POINTER(ct.c_float)), 
      ('iqCount',ct.c_int), 
      ('purge', ct.c_int), 
      ('dataRemaining', ct.c_int), 
      ('sampleLoss', ct.c_int), 
      ('sec', ct.c_int), 
      ('milli', ct.c_int)] 

Création d'une instance:

self.iqPurge = ct.c_int(0) 
self.iqDataRemaining = ct.c_int(0) 
self.iqSampleLoss = ct.c_int(0) 
self.secondsRemaining = ct.c_int(0) 
self.millisecondsRemaining = ct.c_int(0) 
self.iqarraySize = ct.c_int(24305) 
self.iqArr = (ct.c_float*48611)() 
self.saIQPacketData = IQPacketData(self.iqArr, 
            self.iqarraySize, 
            self.iqPurge, 
            self.iqDataRemaining, 
            self.iqSampleLoss, 
            self.secondsRemaining, 
            self.millisecondsRemaining) 

Et d'appeler enfin la fonction:

err = self.dll.saGetIQData(self.deviceHandle,ct.pointer(self.saIQPacketData)) 

Quelques notes: Le paramètre de taille de tableau est la moitié de la taille réelle du tableau. La fonction place 2 flottants d'entrelacement dans le tableau pour chaque échantillon (données de QI complexes).

Conversion du pointeur de tableau vers un tableau de python est fait à l'aide Numpy:

np.fromiter(self.iqArr,dtype=np.float,count=48611) 
+0

Il serait plus rapide d'utiliser 'np.frombuffer (self.iqArr, dtype = np.float32)', mais encore plus rapide d'utiliser le tableau NumPy directement, par exemple. 'self.iqArr = np.zeros ((48611,), dtype = np.float32);' 'self.saIQPacketData = IQPacketData (self.iqArr.ctypes.data_as (ct.POINTER (ct.c_float)), ...) '. – eryksun

+0

Merci @eryksun, je vais essayer. – wgebers