为什么我在这里遇到分段错误? [Python ctypes]

时间:2017-07-23 00:58:51

标签: python c++ ctypes

我对ctypes很新,我在下面的简单程序中遇到错误。

Foo.cpp中

class Foo {
public:
    int bar;
    Foo(int bar): bar(bar) {}
};

extern "C" {
    Foo * Foo_new(int bar) {
        return new Foo(bar);
    }

    int Foo_bar(Foo *foo) {
        return foo->bar;
    }
}

foo.py

import ctypes

libfoo = ctypes.CDLL('libfoo.so')


class Foo:
    def __init__(self, bar):
        self.foo = libfoo.Foo_new(bar)

    def bar(self):
        return libfoo.Foo_bar(self.foo)


foo = Foo(5)
print(foo.bar())

当我调用libfoo.Foo_bar(self.foo)时会发生细分错误,但根据this answer,我认为我需要做的就是通过self.foo做一个强引用,这样它就不是垃圾了集。

我的猜测是Foo是在CPP文件的堆栈上进行的,因此在进行函数调用后会立即擦除它。在任何情况下,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

您必须显式地包装参数和返回类型,否则ctypes将假设某些可能或可能不起作用的任意默认值。要将指针包装到类Foo,我使用指向void c_void_p的指针。我不确定这是否是正确的方法,但似乎有效。

import ctypes

libfoo = ctypes.CDLL('libfoo.so')

libfoo.Foo_new.argtypes = [ctypes.c_int]
libfoo.Foo_new.restype = ctypes.c_void_p

libfoo.Foo_bar.argtypes = [ctypes.c_void_p]
libfoo.Foo_bar.restype = ctypes.c_int

class Foo:
    def __init__(self, bar):
        self.foo = libfoo.Foo_new(bar)

    def bar(self):
        return libfoo.Foo_bar(self.foo)

foo = Foo(5)
print(foo.bar())

我通常采用不同的途径通过使用SWIG生成Python扩展来将C ++代码与Python接口。因此,我会写一个文件test.h

class Foo {
public:
    int bar;
    Foo(int bar): bar(bar) {}
};

然后我会写一个SWIG接口文件test.i

%module test
%{
#include "test.h"
%}
%include "test.h"

然后我在终端

执行
$ swig -python -c++ test.i
$ c++ -fpic -shared -I/usr/include/python2.7 test_wrap.cxx -o _test.so

然后我可以用Python脚本编写

from test import Foo
foo = Foo(5)
print foo.bar