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



我对ctypes很陌生,下面的简单程序出现错误。

傅.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)时会发生分段错误,但根据这个答案,我认为我需要做的就是通过self.foo进行强引用,这样它就不会被垃圾回收。

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

您必须显式包装参数和返回类型,否则ctypes将假定一些可能有效也可能无效的任意默认值。 为了将指针包装到类Foo,我会使用指针来 voidc_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())

我通常采用不同的路径来使用 Python C++代码进行交互,方法是使用 SWIG 生成 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

最新更新