【问题标题】:Passing Structs in Ctypes在 Ctypes 中传递结构
【发布时间】:2013-06-06 19:23:30
【问题描述】:

我一直在尝试在 Ctypes 中传递一个结构。但是函数调用抛出了格式错误。

这是我的 C 函数:

typedef struct Point2Struct {   
    double x, y;
    } Point2;

Point2 test(Point2 k)
{
  return k;
}

python调用如下:

class Point2(Structure):
    _fields_ = [('x',c_double),('y',c_double)]

lib.test.argtypes=[Point2]
lib.test.restype=Point2
p = Point2(1.1, 2.2)

g = lib.test(p)

print g.x, g.y

当我通过 CDLL 调用函数时,我得到:

ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention

使用 WinDLL,我得到:

ValueError: Procedure probably called with too many arguments (16 bytes in excess)

我在 Windows 7 下使用 (Mingw) gcc 将 C 代码编译成 DLL。

 gcc -shared -o test.dll test.o

我也尝试使用 .so 文件:

gcc -shared -Wl,-soname,test-o test.so -fPIC test.c

但是我得到了同样的错误。

我做错了什么?我应该使用任何特定选项进行编译吗?

【问题讨论】:

  • 您是否尝试过将__declspec(dllexport)__cdecl 显式添加到函数中?或者,您是否尝试过编写 C 代码,以与 ctypes 相同的方式加载和使用您的 DLL?

标签: python ctypes


【解决方案1】:

为了处理大于 8 字节的聚合返回,MinGW 和 Microsoft 的编译器都在调用者中隐式传递一个指向本地内存的指针。看起来你的 gcc 版本默认在 callee 中弹出这个指针。但是,ctypes/libffi 是用 Visual Studio 构建的,并且需要 Microsoft 的约定,它在 caller 中处理这个问题。这就是它抱怨缺少 4 个字节的原因。

如果您使用 gcc 4.6+,则有一个 function attribute 来启用 Microsoft 的约定:

callee_pop_aggregate_return (number)

在 32 位 i?86-- 目标上,您可以通过这些属性控制内存中的聚合返回,如果调用者负责将隐藏指针与其余参数一起弹出- 数字等于 0 - 或者如果被调用者负责弹出隐藏指针 - 数字等于 1。默认的 i386 ABI 假定被调用者为隐藏指针弹出堆栈。

gcc 4.7 似乎使用 Microsoft 约定作为 Windows 目标的默认设置:

注意,在 32 位 i386 Windows 目标上,编译器假定调用者弹出隐藏指针的堆栈。

在 Windows 上使用 gcc 4.6.3 进行测试时,它仍然使用“默认 i386 ABI”。设置函数属性解决了问题:

Point2 test(Point2 k)
    __attribute__((callee_pop_aggregate_return(0)));

当然,您的里程可能会有所不同。更好的是,如果您可以控制规范,我认为只使用通过引用传递的显式输出参数会更简单。

【讨论】:

  • 谢谢。我想我会通过传递参考来做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多