在Ctypes中传递结构

时间:2013-06-06 19:23:30

标签: python ctypes

我一直在尝试在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

但我得到了同样的错误。

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

1 个答案:

答案 0 :(得分:2)

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

如果您使用的是gcc 4.6+,则可以使用function attribute来启用Microsoft的约定:

  

callee_pop_aggregate_return(数字)

     

在32位i?86- - 目标上,如果调用者负责将隐藏指针与其余参数一起弹出,则可以通过这些属性控制内存中的聚合返回 - 数字等于零 - 或者如果被调用者负责弹出隐藏指针 - 数字等于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)));

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