将c struct返回到python时出错

时间:2012-07-23 21:31:21

标签: python c ctypes

我有一个c函数:

extern "C"  __declspec(dllexport) MyStruct foo()
{
    MyStruct s = {0, 0}
    return s;
}

MyStruct定义为:

struct MyStruct{
    uInt32   a;
    uInt32   b;
    void *   c;
};

我试图在python中调用该函数,但总是得到如下错误:

  

WindowsError:exception:访问冲突写入0x00000000

如果我从结构中删除void * c,那么它可以工作......

那么我应该如何返回void指针? 谢谢!

4 个答案:

答案 0 :(得分:3)

这几乎可以肯定是由于您的C编译器与ABI上的ctypes库之间在返回对象时存在分歧。在没有看到Python代码的情况下,很难说问题是由于返回类型的Python声明不正确,ctypes库中的错误还是C编译器选择的非标准ABI。

对于最便携的行为,我建议更改函数以通过out参数返回对象,如下所示:

extern "C"  __declspec(dllexport) void foo(MyStruct *ret)
{
    MyStruct s = {0, 0}
    *ret = s;
}

与它接口如下:

class MyStruct(ctypes.Structure):
    _fields_ = [("a", ctypes.c_uint),
                ("b", ctypes.c_uint),
                ("c", ctypes.c_void_p)]

mylib = ctypes.cdll.LoadLibrary('mylibrary')
foo = mylib.foo
foo.argtypes = [ctypes.POINTER(MyStruct)]

x = MyStruct()
foo(ctypes.byref(x))
# x should now have the return value from the C code

答案 1 :(得分:1)

我不认为你是在分配void* c。我没有看到任何地方,但好像它稍后被读取(即access violation writing 0x00000000,一个NULL指针)。因此,c需要在解除引用之前初始化为某些内容。

似乎c的值恰好是0,但并非必须如此。它没有静态存储持续时间,并且您没有对其进行初始化(您只使用a初始化b{0, 0}),因此c可以具有任何值。碰巧的是,在我的测试用例中,c驻留在已初始化为0的内存区域(即使在发布中)。这不能保证。

我敢打赌你做的事情如下:

MyStruct s = foo();
*((some_type*)s.c) = some_value;  // BLAMOOO! c is uninitialized

您尚未发布使用返回值的代码,因此这是我能给您的最佳猜测。

答案 2 :(得分:0)

如果您展示了Python代码,那将会有所帮助。您需要定义foo的结构和返回类型:

from ctypes import *

class MyStruct(Structure):
    _fields_ = [
        ('a',c_int),
        ('b',c_int),
        ('c',c_void_p)]

mydll = CDLL('mydll')
mydll.foo.restype = MyStruct

r = mydll.foo()
print r.a
print r.b
print r.c

答案 3 :(得分:-2)

在堆上分配您的结构并返回指向它的指针,而不是在堆栈上分配它。当您在堆栈上分配内容时,它们是短暂的,即,当从子例程返回时,它们会被机器自动释放。

查询mallocman malloc)/见此处:http://linux.die.net/man/3/malloc