5 votes

Comment puis-je passer un tableau à une bibliothèque partagée (.dll) écrite en c avec python ?

Le code de fonction du fichier test.dll :

double __cdecl add(int len,double array[]){}

(et je l'ai testé en vc)

code python :

import ctypes
from ctypes import *

N=...
arr=(c_double*N)()
...
...
dll=CDLL("test.dll")
sum=dll.add(c_int(N),byref(arr))

print sum

mais le code python ne fonctionne pas, et la "somme" est toujours égale à N (par exemple, lorsque N=10, il imprime "somme=10"). Quel est le problème ?

9voto

Iain Rist Points 856

Passer un tableau dans ctypes reflète le passage d'un tableau en C, c'est-à-dire que vous n'avez pas besoin de passer une référence au tableau puisque celui-ci est déjà une référence à son premier élément.

from ctypes import *

N = ...
arr=(c_double*N)()
dll=CDLL("test.dll")
sum=dll.add(c_int(N),arr)

print sum

Un exemple de ceci peut être vu dans la documentation ctypes sous la rubrique section callbacks lors de la discussion sur l'interfaçage avec qsort.

Edit : Selon le commentaire de David Heffernan, vous avez également besoin d'un dll.add.restype = c_double sinon ctypes supposera que le type retourné est c_int .

0voto

Antti Haapala Points 11542

Le problème ici est que la fonction est définie comme suit

double __cdecl add(int len, double array[]) { }

Cependant, à moins que vous ne spécifiez le type de valeur de retour, ctypes prend par défaut la valeur suivante int . Cela revient à déclarer la fonction en C comme suit

int __cdecl add(int len, double array[]);

Parce que la déclaration et la définition ne correspondent pas, votre code a comportement indéfini c'est-à-dire :

- Une fonction est définie avec un type qui n'est pas compatible avec le type (de l'expression) pointé par l'expression qui dénote la fonction appelée (6.5.2.2).


Dans ce cas précis, vous travaillez sur une architecture où les valeurs entières et à virgule flottante sont renvoyées dans des registres. int y double Les valeurs de retour sont stockées dans différents registres. Maintenant, le registre qui contient la valeur de retour de type int dans cette ABI se trouve contenir le N comme un reliquat. La valeur de retour correcte était contenue dans un registre à virgule flottante, mais elle n'a jamais été utilisée, car ctypes s'attendait à obtenir une valeur int .

La solution correcte est donc de faire

dll.add.restype = c_double

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X