【问题标题】:ctypes/C++ segfault accessing member variablesctypes/C++ 段错误访问成员变量
【发布时间】:2023-03-02 23:17:01
【问题描述】:

我对 python ctypes 模块并不陌生,但这是我第一次尝试在一个代码中结合 C++、C 和 Python。我的问题似乎与Seg fault when using ctypes with Python and C++ 非常相似,但我似乎无法以同样的方式解决问题。

我有一个名为 Header.cpp 的简单 C++ 文件:

#include <iostream>

class Foo{
   public:
      int nbits;
      Foo(int nb){nbits = nb;}
      void bar(){ std::cout << nbits << std::endl; }
};

extern "C" {
   Foo *Foo_new(int nbits){ return new Foo(nbits); }
   void Foo_bar(Foo *foo){ foo->bar(); }
}

我使用以下方法编译到共享库:

g++ -c Header.cpp -fPIC -o Header.o
g++ -shared -fPIC -o libHeader.so  Header.o

还有一个名为 test.py 的简单 Python 包装器:

import ctypes as C
lib = C.CDLL('./libHeader.so')

class Foo(object):
    def __init__(self,nbits):
        self.nbits = C.c_int(nbits)
        self.obj = lib.Foo_new(self.nbits)

    def bar(self):
        lib.Foo_bar(self.obj)

def main():
    f = Foo(32)
    f.bar()

if __name__ == "__main__":
    main()

我希望当我调用 test.py 时,我应该将数字 32 打印到屏幕上。但是,我得到的只是一个分段错误。如果我更改构造函数以返回堆栈上的类实例(即没有new 调用)然后传递对象,程序按预期执行。此外,如果我更改Foo 类中的bar 方法,使其不使用nbits 成员,则程序不会出现段错误。

我对 C++ 的了解有限,但是我可以在 C 和 C++ 中实现这个函数,但在 Python 中却不行,这有点令人困惑。任何帮助将不胜感激。

更新:多亏了下面的cmets之一,问题已经解决了。在这种情况下,需要为 C 函数显式声明 restype 和 argtypes。即在python代码中添加了以下内容:

lib.Foo_new.restype  = C.c_void_p
lib.Foo_new.argtypes = [C.c_int32]
lib.Foo_bar.restype  = None
lib.Foo_bar.argtypes = [C.c_void_p]

【问题讨论】:

  • 为我工作。也可能勘误:我假设您使用 -fPIC 开关编译 Header.cpp?
  • 也在这里工作。请提供段错误的 gdb 回溯。
  • 也适合我。您将指向 Foo 的指针作为 C int 传递,这可能会失败。尝试指定函数 argtypes 和 restype,例如lib.Foo_new.restype = C.c_void_p;lib.Foo_new.argtypes = [C.c_int32];lib.Foo_bar.restype = None;lib.Foo_bar.argtypes = [C.c_void_p]
  • @cgohlke:一针见血,问题解决了。谢谢。
  • 通常传递整数和指针不需要声明的类型,但它可能与将 c_int(32) 传递给 Foo_new 而不仅仅是 Python 整数有关。

标签: c++ python ctypes


【解决方案1】:

我会尝试以下方法:

extern "C"
{
    Foo *Foo_new(int nbits)
    {
        Foo *foo = new Foo(nbits);
        printf("Foo_new(%d) => foo=%p\n", nbits, foo);
        return foo;
    }
    void Foo_bar(Foo *foo)
    {
        printf("Foo_bar => foo=%p\n", foo);
        foo->bar();
    }
 }

查看foo 的值是否匹配。

此外,您可能希望查看 Boost.Python 以简化创建 C++ 对象的 Python 绑定。

【讨论】:

  • 在这种情况下,要包装的代码量非常少,因此我认为使用 Boost.Python 会矫枉过正并添加不必要的依赖项。
猜你喜欢
  • 1970-01-01
  • 2019-08-02
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多