在Ctypes中传递结构 [英] Passing Structs in Ctypes
问题描述
我一直试图在Ctypes中传递一个结构。但是函数调用引发格式错误。
I have been trying to pass a struct in Ctypes. But the function call is throwing a format error.
这是我的C函数:
typedef struct Point2Struct {
double x, y;
} Point2;
Point2 test(Point2 k)
{
return k;
}
python调用如下:
The python call is as follows:
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调用函数时,我得到:
When I call the function through CDLL, I get:
ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention
使用WinDLL,我得到:
with WinDLL, I get:
ValueError: Procedure probably called with too many arguments (16 bytes in excess)
我将C代码编译为DLL在Windows 7下使用(Mingw)gcc。
I compiled the C code into a DLL using (Mingw) gcc under Windows 7.
gcc -shared -o test.dll test.o
我还尝试使用.so文件,其内容如下:
I also tried using a .so file with:
gcc -shared -Wl,-soname,test-o test.so -fPIC test.c
但是我遇到了同样的错误。
But I get the same errors.
我在做什么错?我应该使用任何特定的选项进行编译吗?
What am I doing wrong ? Should I compile with any specific option ?
推荐答案
要处理大于8个字节的汇总返回值,MinGW和Microsoft的编译器都隐式地传递了一个指向调用方本地内存的指针。看来您的gcc版本默认在 callee 中弹出该指针。但是,ctypes / libffi是使用Visual Studio构建的,并且需要Microsoft的约定,该约定可以在 caller 中进行处理。这就是为什么它抱怨缺少4个字节的原因。
To handle aggregate returns larger than 8 bytes, both MinGW and Microsoft's compiler implicitly pass a pointer to local memory in the caller. It looks like your version of gcc defaults to popping this pointer in the callee. However, ctypes/libffi was built with Visual Studio and expects Microsoft's convention, which handles this in the caller. That's why it complains about missing 4 bytes.
如果您使用的是gcc 4.6+,则会有一个函数属性以启用Microsoft的约定:
If you're using gcc 4.6+, there's a function attribute to enable Microsoft's convention:
callee_pop_aggregate_return(数字)
callee_pop_aggregate_return (number)
在32位i?86- -目标上,可以通过这些属性来控制聚合如果调用方负责将隐藏的指针与其余参数(数字等于零)一起弹出,或者如果被调用方负责弹出隐藏的指针(数字等于1),则在内存中返回。默认的i386 ABI假定被调用者为隐藏指针弹出堆栈。
On 32-bit i?86-- targets, you can control by those attribute for aggregate return in memory, if the caller is responsible to pop the hidden pointer together with the rest of the arguments - number equal to zero -, or if the callee is responsible to pop hidden pointer - number equal to one. The default i386 ABI assumes that the callee pops the stack for hidden pointer.
似乎gcc 4.7使用Microsoft约定作为默认值。 Windows目标:
It seems gcc 4.7 uses the Microsoft convention as the default for Windows targets:
请注意,在32位i386 Windows目标上,编译器假定调用者弹出堆栈以获取隐藏的指针。
Note, that on 32-bit i386 Windows targets the compiler assumes that the caller pops the stack for hidden pointer.
在Windows上使用gcc 4.6.3进行测试时,它仍然使用了默认的i386 ABI。设置函数属性可以解决问题:
With my test using gcc 4.6.3 on Windows, it still used the "default i386 ABI". Setting the function attribute solved the problem:
Point2 test(Point2 k)
__attribute__((callee_pop_aggregate_return(0)));
当然,您的里程可能会有所不同。更好的是,如果您可以控制规范,我认为仅使用通过引用传递的显式输出参数会更简单。
Your mileage may vary, of course. Better still, if you're in control of the spec I think it's simpler to just use an explicit output parameter passed by reference.
这篇关于在Ctypes中传递结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!