2017-07-15 3 views
1

Je voudrais passer une variable ByteArray de mon programme Python à ma DLL écrite en C afin d'accélérer un traitement spécifique qui est trop lent en Python. J'ai traversé le Web, essayé des Ctypes avec des combinaisons de byref, cast, memoryviews, addressof, mais rien ne fonctionne. Existe-t-il un moyen simple d'y parvenir sans copier mon ByteArray dans quelque chose d'autre qui passera? Voici ce que je suis en train de faire:Passer un ByteArray de Python à la fonction C

/* My C DLL */ 
__declspec(dllexport) bool FastProc(char *P, int L) 
{ 
    /* Do some complex processing on the char buffer */ 
    ; 
    return true; 
} 

# My Python program 
from ctypes import * 
def main(argv): 
    MyData = ByteArray([1,2,3,4,5,6]) 
    dll = CDLL('CHELPER.dll') 
    dll.FastProc.argtypes = (c_char_p, c_int) 
    dll.FastProc.restype = c_bool 

    Result = dll.FastProc(MyData, len(MyData)) 
    print(Result) 

Mais je reçois une erreur de type lors du passage du premier paramètre (MyData) à la fonction C.

Y at-il une solution qui ne nécessite pas trop de frais généraux et qui gaspillerait les avantages de ma fonction C?

Olivier

+0

Qu'est-ce 'ByteArray'? Ne devrait-il pas être «bytearray» (tout en minuscules)? Utilisez-vous Python 3? –

+0

Oui c'est un bytearray, désolé pour la faute de frappe – Marmotte06

+0

Créez un type de tableau ctypes de même longueur et passez le 'bytearray' à son [' from_buffer'] (https://docs.python.org/3/library/ctypes. html # ctypes._CData.from_buffer) contsructor, par exemple 'L = len (MyData);' 'P = (ctypes.c_char * L) .from_buffer (Mes données);' 'dll.FastProc (P, L)'. – eryksun

Répondre

0

Je suppose que ByteArray est censé être bytearray. Nous pouvons utiliser create_string_buffer pour créer un tampon de caractères mutable qui est un tableau ctypes de c_char. Mais create_string_bufferpas accepter un bytearray, nous devons lui passer un objet bytes pour l'initialiser; heureusement, le casting entre bytes et bytearray est rapide et efficace.

Je n'ai pas votre DLL, donc pour tester que le tableau se comporte correctement, j'utiliserai la fonction libc.strfry pour mélanger ses caractères.

from ctypes import CDLL, create_string_buffer 

libc = CDLL("libc.so.6") 

# Some test data, NUL-terminated so we can safely pass it to a str function. 
mydata = bytearray([65, 66, 67, 68, 69, 70, 0]) 
print(mydata) 

# Convert the Python bytearray to a C array of char 
p = create_string_buffer(bytes(mydata), len(mydata)) 

#Shuffle the bytes before the NUL terminator byte, in-place. 
libc.strfry(p) 

# Convert the modified C array back to a Python bytearray 
newdata = bytearray(p.raw) 
print(newdata) 

sortie typique

bytearray(b'ABCDEF\x00') 
bytearray(b'BFDACE\x00') 
+0

Mmmm, à première vue je pensais que vous aviez trouvé la solution, mais je suis allé à la doc de create_string_buffer et je crois comprendre qu'il crée un nouvel objet et xopies l'original bytearray en elle. C'est pourquoi, à la fin, vous imprimez newdata au lieu de mydata. Je préférerais de loin que ma fonction fonctionne sur l'original bytearray in-place, sans aucune copie. Bytearrays étant mutable qui ne devrait pas violer les lois Python. J'ai trouvé des messages recommandant SWIG pour réaliser ce que je veux, j'ai besoin de creuser dans ce domaine. Merci beaucoup pour votre aide, j'ai découvert la fonction create_string_buffer – Marmotte06