【问题标题】:Error when using ctypes module to acess a DLL written in C使用 ctypes 模块访问用 C 编写的 DLL 时出错
【发布时间】:2011-10-07 05:45:45
【问题描述】:

我有一个带有一个函数的 DLL,它得到五个双精度数和一个整数:

__declspec(dllexport)  struct res ITERATE(double z_r,double z_i,double c_r, double c_i, int iterations, double limit)

它重新调整了一个自定义结构,称为 res,它由一个三双数组组成:

struct res {
   double arr[3];
};

要返回值,我这样做:

struct res result;      /*earlier in the code */

result.arr[0] = z_real; /*Just three random doubles*/
result.arr[1] = z_imag;
result.arr[2] = value;
return result;

我已经用 MinGW 编译了它,我正在尝试在 python 中使用它来做这样的事情:

form ctypes import *

z = [0.0,0.0]
c = [1.0,1.0]
M = 2.0

MiDLL = WinDLL("RECERCATOOLS.dll")
MiDLL.ITERATE.argtypes = [c_double, c_double, c_double, c_double,c_int,c_double]
MiDLL.ITERATE(z[0],z[1],c[0],c[1],100,M) #testing out before assigning the result to anything.

但是,每当我尝试使用这些值调用函数时,它都会向我抛出这个:

WindowsError: exception: access violation writing 0x00000000

我也不知道如何捕获我声明的自定义结构并将其每个元素转换为 Python 浮点数。我调查了this PyDocs link,但无济于事。

提前谢谢你。

编辑:

这是使用的原始(根据建议修改)头文件(“mydll.h”):

#ifndef MYDLL_H
#define MYDLL_H

extern "C" __declspec(dllexport)
#define EXPORT_DLL __declspec(dllexport)

EXPORT_DLL void ITERATE(struct res*, double z_r,double z_i,double c_r, double c_i, int iterations, double limit)


#endif

并且,如果它可能有问题,代码文件(它很短,只有一个功能):

#include <stdio.h>
#include <complex.h>

struct res {
   double arr[3];
};

void __declspec(dllexport) ITERATE(struct res* result,double z_r,double z_i,double c_r, double c_i, int iterations, double limit)
{
/* The purpose of this function is, given two complex numbers,
   an iteration number and a limit, apply a formula to these
   two numbers for as many iterations as specified.

   If at any iteration the result of the formula is bigger than
   the limit, stop and return the number and the iteration it reached.

   If after iterating they are still inside the limit, return the
   number after all the iterations and the number of iterations
   it has gone through.

   Complex numbers are composed of a real part and an imaginary part,
   and they must be returned separately.
*/
double complex z = z_r + z_i*I;
double complex c = c_r + c_i*I;
int actual_iter;

for (actual_iter = 1; actual_iter <= iterations; actual_iter++)
    {
    z = z*z + c;
    if (cabs(z) > limit)
        {
        double value = actual_iter;
        double z_real = creal(z);
        double z_imag = cimag(z);
        result.arr[0] = z_real;
        result.arr[1] = z_imag;
        result.arr[2] = value;
        }
    }
double value = iterations;
double z_real = creal(z);
double z_imag = cimag(z);
result.arr[0] = z_real;
result.arr[1] = z_imag;
result.arr[2] = value;
}

int main()
{
return 0;
}

【问题讨论】:

  • 现在您已经进行了此更改,您还需要修改您的 python 程序以将指向该结构的指针作为第一个参数传递。查看您发布的链接,了解您是如何做到这一点的。如果这不起作用,请发布与修改后的 C 代码匹配的 Python 代码。
  • 是的,通过查看 PyDocs 和 SO 的人员,我已经能够做到这一点,我终于让它工作了。 :D
  • 你可以用我的回答:stackoverflow.com/questions/7586504/…

标签: python c dll types ctypes


【解决方案1】:

返回这样的结构存在问题。并非所有编译器都以相同的方式返回此类结构。我宁愿把函数声明改成这样:

void __declspec(dllexport) ITERATE(struct res* result, double z_r,double z_i, 
    double c_r, double c_i, int iterations, double limit);

这样结构体就在用户的内存中,并且结构体的返回方式没有歧义。

当然,正如 David 所说,您可能必须使用不同的调用约定。

【讨论】:

  • 我不完全理解在 args 中添加指向结构的指针是什么意思(如您所见,我不是任何类型的 C 开发人员,我没有太多经验C)。你的意思是我应该提供一个指向 struct res 对象的指针,以便函数能够管理和修改它,但函数实际上没有返回任何东西?好的,这很有意义,但是,如何初始化可以作为struct res 对象传递的python 对象?像这样:Arr3 = c_double*3(在 Python 中)然后将其作为函数的第一个参数传递?
  • Arr3 = (c_double*3)() 然后用byref(arr), IIRC 传递它
  • 不同的编译器有不同的方式来返回这样的结构。事实是它们必须传递(对你不可见,编译器会这样做)一个指向它们必须返回的结构的指针,以便它们可以将内容写入那块内存。但是如何将此指针传递给 C 函数可能因编译器而异。因此,尽管您认为编译器 A 编译的函数与编译器 B 编译的函数相同,但它们可能在指针传递方式上有所不同。最好自己显式传递,这样就没有歧义了。这就是我所做的更改。
  • FWIW,当我不得不使用这样的函数返回结构(或数组,同样的问题)而不是 C(在我的例子中是 Delphi)时,我已经被这个问题困扰了好几次。我了解到,当 C 函数返回结构或数组时,必须始终小心,最好避免这种情况。
  • +1 我认为这很有可能解释问题。
猜你喜欢
  • 1970-01-01
  • 2021-11-03
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多